Anda di halaman 1dari 498

Bienvenido al curso de Visual Basic 2005

En este curso podrs aprender a desarrollar aplicaciones con la prxima generacin


de herramientas de desarrollo Microsoft Visual Studio 2005. Veremos las
principales diferencias con Visual Basic 6, tanto a nivel del lenguaje como de la
infraestructura de desarrollo utilizada, y acabaremos desarrollando una aplicacin
real con los conceptos aprendidos. Al final de cada leccin tendrs disponible un
video en el que podrs ver los conceptos explicados de forma prctica sobre el
entorno de Visual Studio 2005.
Te recomendamos tambin que veas la aplicacin MSDN Video, que desarrollaremos
al finalizar el curso y de la que podrs descargar su cdigo fuente y videos
explicativos.
Recuerda que si quieres poner en prctica este curso tienes disponibles una versin
sin limitaciones de Visual Basic 2005 Express, que incluye la base de datos SQL
Server 2005 Express. Puedes descargarla en el rea de versiones Express.
Disfruta del curso!

1
Introduccin
En esta primera leccin veremos los tipos de datos que .NET Framework pone a
nuestra disposicin, as mismo veremos las diferencias con respecto a los tipos de
datos de Visual Basic 6.0 y las equivalencias entre los tipos de ambos entornos, de
esta forma nos resultar ms fcil familiarizarnos. Aunque no debemos olvidar que
en .NET los tipos de datos tienen un tratamiento, en algunos casos, especial que
pueden llevarnos a confusin, por tanto en los casos que pueda existir esa
posibilidad de funcionamiento diferente, veremos ejemplos de cmo los
manejbamos en VB6 y cmo tendremos que usarlos desde Visual Basic 2005.
A continuacin daremos un repaso a conceptos bsicos o elementales sobre los
tipos de datos, que si bien nos sern familiares, es importante que lo veamos para
poder comprender mejor cmo estn definidos y organizados los tipos de datos
en .NET y de paso veremos las equivalencias con respecto a Visual Basic 6.0.

Tipos de datos de .NET
Visual Basic 2005 est totalmente integrado con .NET Framework, por tanto los
tipos de datos que podremos usar con este lenguaje sern los definidos en este
"marco de trabajo", por este motivo vamos a empezar usando algunas de las
definiciones que nos encontraremos al recorrer la documentacin que acompaa a
este lenguaje de programacin.
Los tipos de datos que podemos usar en Visual Basic 2005 son los mismo tipos de
datos definidos en .NET Framework y por tanto estn soportados por todos los
lenguajes que usan esta tecnologa. Estos tipos comunes se conocen como el
Common Type System, (CTS), que traducido viene a significar el sistema de tipos
comunes de .NET. El hecho de que los tipos de datos usados en todos los
lenguajes .NET estn definidos por el propio Framework nos asegura que
independientemente del lenguaje que estemos usando, siempre utilizaremos el
mismo tipo interno de .NET, si bien cada lenguaje puede usar un nombre (o alias)
para referirse a ellos, aunque lo importante es que siempre sern los mismos datos,
independientemente de cmo se llame en cada lenguaje. Esto es una gran ventaja,
ya que nos permite usarlos sin ningn tipo de problemas, al menos en cuanto a lo
que a conversiones se refiere, cosa que no ocurra en Visual Basic 6.0, cuando, por
ejemplo, queramos interoperar con otros lenguajes, como era el caso de C/C++, el
caso ms claro era a la hora de acceder a funciones incluidas en libreras (DLL), por
ejemplo del API de Windows, siempre debamos tener en cuenta que ciertos tipos
de datos no eran equivalentes, el ejemplo ms claro lo tenemos en las cadenas, ya
que no es lo mismo una cadena de VB6 que una de C/C++. En .NET este problema
de "compatibilidad" no existe, por la sencilla razn de que una cadena de Visual
Basic es lo mismo que una cadena de C#, ya que estos dos lenguajes usan el tipo
definido en .NET Framework.

En los siguientes enlaces tenemos los temas a tratar en esta primera leccin del
mdulo sobre las caractersticas del lenguaje Visual Basic 2005.
2

Tipos primitivos
o Sufijos o caracteres y smbolos identificadores para los tipos
o Tipos por valor y tipos por referencia
Variables y constantes
o Consejo para usar las constantes
o Declarar variables
o Declarar variables y asignar el valor inicial
o El tipo de datos Char
o Obligar a declarar las variables con el tipo de datos
o Aplicar Option Strict On a un fichero en particular
o Aplicar Option Stict On a todo el proyecto
o Ms opciones aplicables a los proyectos
Enumeraciones: Constantes agrupadas
o El nombre de los miembros de las enumeraciones
o Los valores de una enumeracin no son simples nmeros
Arrays (matrices)
o Declarar e inicializar un array
o Cambiar el tamao de un array
o Eliminar el contenido de un array
o Los arrays son tipos por referencia
Tipos primitivos

Veamos en la siguiente tabla los tipos de datos definidos en .NET Framework y los
alias utilizados en Visual Basic 2005, as como el equivalente de VB6.

.NET Frameor! VB 2005 VB"
System.Boolean Boolean Boolean *
System.Byte Byte Byte
System.Int16 Short Integer
System.Int32 Integer Long
System.Int64 Long N.A.
System.Single Single Single
System.Double Double Double
System.Decimal Decimal Currency *
System.Char Char N.A. (ChrW)
3
System.String String String *
System.Object Object Variant / Object *
System.DateTime Date Date *

System.SByte SByte N.A.
System.UInt16 UShort N.A.
System.UInt32 UInteger N.A.
System.UInt64 ULong N.A.
Ta#la $.$. Tipos de datos % e&uivalencia entre len'ua(es
En la columna de equivalencias con VB6 tenemos algunos indicados con N.A., estos
tipos no tienen equivalencia, por otro lado, los marcados con un asterisco (*) no
tienen equivalencia directa, pero el o los tipos indicados seran los que ms se
aproximaran. El caso del tipo String es un caso especial, realmente un String de
.NET es casi como uno de VB6, con la diferencia de que las cadenas en .NET son
inmutables, es decir, una vez que se han creado no se pueden modificar y en caso
de que queramos cambiar el contenido, .NET se encarga de usar la anterior y crear
una nueva cadena, por tanto si usamos las cadenas para realizar concatenaciones
(unin de cadenas para crear una nueva), el rendimiento es inferior al que tenamos
en VB6, si bien existe una clase en .NET que es ideal para estos casos y cuyo
rendimiento es, si no superior al menos parecido al de VB6: la clase StringBuilder.
Las ltimas filas mostradas en la tabla son tipos especiales que si bien son parte del
sistema de tipos comunes (CTS) no forman parte de la Common Language
Specification (CLS), es decir la especificacin comn para los lenguajes
"compatibles" con .NET, por tanto, si queremos crear aplicaciones que puedan
interoperar con todos los lenguajes de .NET, esos tipos no debemos usarlos como
valores de devolucin de funciones ni como tipo de datos usado en los argumentos
de las funciones, propiedades o procedimientos.

Los tipos mostrados en la tabla 1 son los tipos primitivos de .NET y por extensin de
Visual Basic 2005, es decir son tipos "elementales" para los cuales cada lenguaje
define su propia palabra clave equivalente con el tipo definido en el CTS de .NET
Framework. Todos estos tipos primitivos podemos usarlos tanto por medio de los
tipos propios de Visual Basic, los tipos definidos en .NET o bien como literales. Por
ejemplo, podemos definir un nmero entero literal indicndolo con el sufijo I:
12345I o bien asignndolo a un valor de tipo Integer o a un tipo Sytem.Int32 de
.NET. La nica excepcin de los tipos mostrados en la tabla 1 es el tipo de datos
Object, este es un caso especial del que nos ocuparemos en la prxima leccin.

4
Sufios o caracteres y s!mbolos identificadores para los tipos
Cuando usamos valores literales numricos en Visual Basic 2005, el tipo de datos
que le asigna el compilador es el tipo Double, por tanto si nuestra intencin es
indicar un tipo de datos diferente podemos indicarlos aadiendo una letra como
sufijo al tipo, esto es algo que los ms veteranos de VB6 ya estarn acostumbrados,
e incluso los ms noveles tambin, en Visual Basic 2005 algunos de ellos se siguen
usando, pero el tipo asociado es el equivalente al de este nuevo lenguaje (tal como
se muestra en la tabla 1), por ejemplo para indicar un valor entero podemos usar la
letra I o el signo ), de igual forma, un valor de tipo entero largo (Long) lo
podemos indicar usando * o +, en la siguiente tabla podemos ver los caracteres o
letra que podemos usar como sufijo en un literal numrico para que el compilador lo
identifique sin ningn lugar a dudas.

Tipo de datos S,m#olo -ar.cter
Short N.A. S
Integer % I
Long & L
Single ! F
Double # R
Decimal @ D
UShort N.A. US
UInteger N.A. UI
ULong N.A. UL
Ta#la $.2. Sufi(os para identificar los tipos de datos
El uso de estos caracteres nos puede resultar de utilidad particularmente para los
tipos de datos que no se pueden convertir en un valor doble.
Por ejemplo, si queremos asignar este valor literal a un tipo Decimal:
12345678901234567890, tal como vemos en la figura 1, el IDE de Visual Basic
2005 nos indicar que existe un error de desbordamiento (Oerflo!) ya que esa
cifra es muy grande para usarlo como valor Double, pero si le agregamos el sufijo /
o 0 ya no habr dudas de que estamos tratando con un valor Decimal.

5
Fi'ura $.$. Error de des#ordamiento al intentar asi'nar un valor /ou#le a
una varia#le /ecimal


Tipos por valor % tipos por referencia
Los tipos de datos de .NET los podemos definir en dos grupos:
Tipos por valor
Tipos por referencia
Los tipos por valor son tipos de datos cuyo valor se almacena en la pila o en la
memoria "cercana", como los numricos que hemos visto. Podemos decir que el
acceso al valor contenido en uno de estos tipos es directo, es decir se almacena
directamente en la memoria reservada para ese tipo y cualquier cambio que
hagamos lo haremos directamente sobre dicho valor, de igual forma cuando
copiamos valores de un tipo por valor a otro, estaremos haciendo copias
independientes.
Por otro lado, los tipos por referencia se almacenan en el "monto" ("eap) o
memoria "lejana", a diferencia de los tipos por valor, los tipos por referencia lo nico
que almacenan es una referencia (o puntero) al valor asignado. Si hacemos copias
de tipos por referencia, realmente lo que copiamos es la referencia propiamente
dicha, pero no el contenido.
Estos dos casos los veremos en breve con ms detalle.

Varia#les % constantes
Disponer de todos estos tipos de datos no tendra ningn sentido si no los
pudiramos usar de alguna otra forma que de forma literal. Y aqu es donde entran
en juego las variables y constantes, no vamos a contarte qu son y para que sirven,
6
salvo en el caso de las constantes, ya que no todos los desarrolladores las
utilizamos de la forma adecuada.

Conseo para usar las constantes
Siempre que tengamos que indicar un valor constante, ya sea para indicar el
mximo o mnimo permitido en un rango de valores o para comprobar el trmino de
un bucle, deberamos usar una constante en lugar de un valor literal, de esta forma
si ese valor lo usamos en varias partes de nuestro cdigo, si en un futuro decidimos
que dicho valor debe ser diferente, nos resultar ms fcil realizar un solo cambio
que cambiarlo en todos los sitios en los que lo hemos usado, adems de que de esta
forma nos aseguramos de que el cambio se realiza adecuadamente y no tendremos
que preocuparnos de las consecuencias derivadas de no haber hecho el cambio en
todos los sitios que deberamos.
Pero esto no es algo nuevo, las constantes se definen de la misma forma que en
VB6, salvo que ahora podemos obligarnos a indicar el tipo de datos que esa
constante va a contener. Esto lo veremos en la siguiente seccin.

"eclarar variables
La declaracin de las variables en Visual Basic 2005 se hace de la misma forma que
en VB6, o casi, las excepciones vienen dadas, como hemos comentado antes, de la
posibilidad de obligar a definir el tipo de cada variable y de cmo podemos definir
ms de una variable en una misma instruccin Dim.
Para no embrollar mucho la cosa, veamos ejemplos de cmo definir o declarar
variables siguiendo las buenas costumbres, es decir, indicando siempre el tipo de
datos de la variable.
En VB6 podamos definir ms de una variable en una misma instruccin Dim,
aunque dependiendo de cmo hiciramos esa declaracin poda ser que,
normalmente para nuestro pesar, que no todas las variables fuesen del tipo que
"supuestamente" habamos querido indicar.
Por ejemplo, con esta declaracin:
Dim a, b, c As Integer
A primera vista estamos declarando tres variables de tipo Integer, pero realmente
solo declara con el tipo indicado a la ltima variable, las otras dos, se declaran con
tipo #ariant o el tipo de datos predefinido.
En Visual Basic 2005 al usar esa misma lnea de cdigo estamos declarando tres
variables de tipo Integer, esto es algo que debemos tener en cuenta, sobre todo si
nuestra intencin era hacer precisamente lo que VB6 haca, es decir, declarar dos
variables de tipo #ariant y una de tipo Integer.
7

"eclarar variables y asignar el valor inicial
En Visual Basic 2005 tambin podemos inicializar una variable con un valor distinto
al predeterminado, que en los tipos numricos es un cero, en las fechas es el 1 de
enero del ao 1 a las doce de la madrugada (10$20$2000$ $23003004M1) y en
la cadenas es un valor nulo ($ot"ing), para hacerlo, simplemente tenemos que
indicar ese valor, tal como veremos es muy parecido a como se declaran las
constantes. Por ejemplo:
Dim a As Integer = 10
En esa misma lnea podemos declarar y asignar ms variables, pero todas deben
estar indicadas con el tipo de datos:
Dim a As Integer = 10, b As Integer = 25
Por supuesto, el tipo de datos puede ser cualquiera de los tipos primitivos:
Dim a As Integer = 10, b As Integer = 25, s As String = "Hola"
Aunque para que el cdigo sea ms legible, y fcil de depurar, no deberamos
mezclar en una misma instruccin Dim ms de un tipo de datos.

Nota3
Es importante saber que en las cadenas de Visual Basic 2005 el valor
de una variable de tipo String no inicializada NO es una cadena vaca
como ocurra en VB6, sino un valor nulo ($ot"ing).


El tipo de datos C#ar
En Visual Basic 2005 podemos declarar valores de tipo C"ar, este tipo de datos es
un carcter Unicode y podemos declararlo y asignarlo a un mismo tiempo. El
problema con el que nos podemos encontrar es a la hora de indicar un carcter
literal.
Si bien en VB6 no existe el tipo de datos C"ar, si podemos convertir un valor
numrico en un carcter (realmente en una cadena) o bien podemos convertir un
carcter en su correspondiente valor numrico.
Dim c As String
8
c = Chr(65)
Dim n As Integer
n = Asc("A")
En Visual Basic 2005 tambin podemos usar esas mismas funciones, aunque en el
caso de C"r, el valor que devuelve esta funcin es un valor de tipo C"ar, no de tipo
String como ocurre en VB6, pero debido a que un valor de tipo C"ar se puede
convertir en una cadena, podemos hacer una asignacin como la mostrada en el
cdigo anterior sin ningn tipo de problemas.
Si nuestra intencin es asignar un valor C"ar a una variable, adems de la funcin
C"r, podemos hacerlo con un literal, ese valor literal estar encerrado entre comillas
dobles, (al igual que una cadena), aunque para que realmente sea un carcter
debemos agregarle una c justo despus del cierre de las comillas dobles:
Dim c As Char = "A"c


$bligar a declarar las variables con el tipo de datos
La obligatoriedad, a la que hacamos referencia anteriormente, de declarar las
variables y constantes con el tipo de datos adecuado, la podemos aplicar a todo el
proyecto o a un mdulo en particular, para ello tenemos que usar la instruccin
Option Strict On, una vez indicado, se aplicar a todo el cdigo, no solo a las
declaraciones de variable, constantes o al tipo de datos devuelto por las funciones y
propiedades, sino tambin a las conversiones y asignaciones entre diferentes tipos
de datos.
No debemos confundir Option Strict con Option %&plicit, este ltimo, al igual que en
VB6, nos obliga a declarar todas las variables, mientras que el primero lo que hace
es obligarnos a que esas declaraciones tengan un tipo de datos.
Tanto una como la otra tienen dos estados: conectado o desconectado dependiendo
de que agreguemos On u Off respectivamente.
Como recomendacin para buenas prcticas, debemos "conectar" siempre estas dos
opciones, si bien Option %&plicit On ya viene como valor por defecto, cosa que no
ocurre con Option Strict, que por defecto est desconectado.


9
Aplicar $ption Strict $n a un fic#ero en particular
Cuando en VB6 agregbamos un nuevo formulario, mdulo BAS o mdulo de clase,
se agregaba automticamente la instruccin Option %&plicit, en Visual Basic 2005
esta opcin est predefinida y no se agrega a ningn mdulo, pero eso no significa
que no se aplique, aunque siempre podemos escribir esas instrucciones (con el valor
On al final) en cada uno de los mdulos o ficheros de cdigo que agreguemos a
nuestro proyecto. Lo mismo podemos hacer con Option Strict On, en caso de que
nos decidamos a hacerlo, esas lneas de cdigo deben aparecer al principio del
fichero y solamente pueden estar precedidas de comentarios (instrucciones '%( o
lneas iniciadas con una comilla simple).
En la figura 1 mostrada anteriormente tenemos una captura del editor de Visual
Basic 2005 en la que hemos indicado que queremos tener comprobacin estricta.


Aplicar $ption Stict $n a todo el proyecto
Tambin podemos hacer que Option Strict funcione igual que Option %&plicit, es
decir, que est activado a todo el proyecto, en este caso no tendramos que indicarlo
en cada uno de los ficheros de cdigo que formen parte de nuestro proyecto, si bien
solamente ser aplicable a los que no tengan esas instrucciones, aclaremos esto
ltimo: si Option Strict (u Option %&plicit) est definido de forma global al proyecto,
podemos desactivarlo en cualquiera de los ficheros, para ello simplemente habra
que usar esas declaraciones pero usando Off en lugar de On. De igual forma, si ya
est definido globalmente y lo indicamos expresamente, no se producir ningn
error. Lo importante aqu es saber que siempre se usar el estado indicado en cada
fichero, independientemente de cmo lo tengamos definido a nivel de proyecto.
Para que siempre se usen estas asignaciones en todo el proyecto, vamos a ver
cmo indicarlo en el entorno de Visual Basic 2005.
Abrimos el Visual Basic 2005 Express y una vez que se haya cargado, (no hace falta
crear ningn nuevo proyecto, de este detalle nos ocuparemos en breve),
seleccionamos la opcin 5erramientas67pciones... se mostrar un cuadro de
dilogo y del panel izquierdo seleccionamos la opcin 8ro%ectos % soluciones, la
expandimos y seleccionamos Valores predeterminados de VB y veremos ciertas
opciones, tal como podemos comprobar en la figura 1.2:
10
Fi'ura $.2. 7pciones de pro%ectos 9opciones m,nimas:
De la lista despegable 7ption Strict, seleccionamos 7n. Por defecto ya estarn
seleccionadas las opciones 7n de 7ption E;plicit y Binar% de 7ption -ompare,
por tanto no es necesario realizar ningn cambio ms, para aceptar los cambios y
cerrar el cuadro de dilogo, pulsamos en el botn 4ceptar.

Nota3
Aunque en esta captura muestre: C:\vbexpB1 en Default project
location, salvo que lo cambiemos, aparecer el path por defecto
dentro de Mis documentos.

Como podemos observar, aparecen pocas opciones, realmente el IDE de Visual Basic
2005 Express nos muestra las predeterminadas para los desarrolladores de Visual
Basic, si bien, podemos hacer que se muestren todas las disponibles, para hacerlo,
debemos marcar la casilla que est en la parte inferior izquierda en la que podemos
leer: Mostrar todas las confi'uraciones, al seleccionar esa opcin nos mostrar
un nmero mayor de opciones, tal como podemos ver en la figura 1.3:
11
Fi'ura $.<. 7pciones de pro%ectos 9todas las opciones:

Desde este momento el compilador de VB se volver estricto en todo lo relacionado
a las declaraciones de variables y conversiones, tal como vemos en la figura 1.4 al
intentar declarar una variable sin indicar el tipo de datos.
Fi'ura $.=. 4viso de 7ption Strict al declarar una varia#le sin tipo

12
Nota3
Una de las ventajas del IDE (Integrated Deelopment %nironment,
entorno de desarrollo integrado) de Visual Basic 2005 es que nos avisa
al momento de cualquier fallo que cometamos al escribir el cdigo,
este "pequeo" detalle, aunque alguna veces puede llegar a parecer
fastidioso, nos facilita la escritura de cdigo, ya que no tenemos que
esperar a realizar la compilacin para que tengamos constancia de
esos fallos.


%&s opciones aplicables a los proyectos
Aunque en estos mdulos no trataremos a fondo el entorno de desarrollo, ya que la
finalidad de este curso online es tratar ms en el cdigo propiamente dicho, vamos
a mostrar otro de los sitios en los que podemos indicar dnde indicar que se haga
una comprobacin estricta de tipos y, como veremos, tambin podremos indicar
algunas "nuevas peculiaridades" de Visual Basic 2005, todas ellas relacionadas con
el tema que estamos tratando.
Cuando tengamos un proyecto cargado en el IDE de Visual Basic 2005 Express,
(pronto veremos cmo crear uno), podemos mostrar las propiedades del proyecto,
para ello seleccionaremos del men 8ro%ecto la opcin 8ropiedades de
>Nom#re/el8ro%ecto6 y tendremos un cuadro de dilogo como el mostrado en
la figura 1.5.
13
Fi'ura $.5. Fic?a -ompilar de las opciones del pro%ecto actual
Seleccionando la ficha -ompilar, adems de las tpicas opciones de 7ption Strict,
7ption E;plicit y 7ption -ompare, (estas asignaciones solo sern efectivas para
el proyecto actual), tendremos cmo queremos que reaccione el compilador si se
cumple algunas de las condiciones indicadas. Entre esas condiciones, tenemos algo
que muchos desarrolladores de Visual Basic siempre hemos querido tener: Que nos
avise cuando una variable la hemos declarado pero no la utilizamos (Varia#le local
no utili@ada). Al tener marcada esta opcin (normalmente como una
4dvertencia), si hemos declarado una variable y no la usamos en el cdigo,
(siempre que no le hayamos asignado un valor al declararla), nos avisar, tal como
podemos ver en la figura 1.6:
14
Fi'ura $.". 4viso de varia#le no usada

Enumeraciones3 -onstantes a'rupadas
Las enumeraciones no son una novedad de Visual Basic 2005, aunque como
veremos, si lo es la forma de usarlas, e incluso de declararlas. Aunque esos cambios
son menores y la funcionalidad que tenamos en VB6 sigue siendo la misma.
De todas formas echemos un breve repaso a las enumeraciones para que tengamos
los conceptos claros.
Una enumeracin es una serie de constantes que estn relacionadas entre s. La
utilidad de las enumeraciones es ms manifiesta cuando queremos manejar una
serie de valores constantes con nombre, es decir, podemos indicar un valor, pero en
lugar de usar un literal numrico, usamos un nombre, ese nombre es, al fin y al
cabo, una constante que tiene un valor numrico.
En Visual Basic 2005 las enumeraciones pueden ser de cualquier tipo numrico
integral, incluso enteros sin signo, aunque el valor predefinido es el tipo Integer.
Podemos declarar una enumeracin de varias formas:
1- De forma, normal, a la vieja usanza:
n!m Colores
"o#o
$er%e
A&!l
n% n!m
15
En este primer caso, el tipo de datos de cada miembro de la enumeracin ser
Integer.
2- Indicando el tipo de datos que realmente tendr:
n!m Colores As 'ong
"o#o
$er%e
A&!l
n% n!m
En este segundo caso, el valor mximo que podemos asignar a los miembros de una
enumeracin ser el que pueda contener un tipo de datos Long.
3- Indicando el atributo )lags*ttibute, (realmente no hace falta indicar el sufijo
*ttribute cuando usamos los atributos) de esta forma podremos usar los valores de
la enumeracin para indicar valores que se pueden "sumar" o complementar entre
s, pero sin perder el nombre, en breve veremos qu significa esto de "no perder el
nombre".
()lags()* +
n!m Colores As ,-te
"o#o = 1
$er%e = 2
A&!l = .
n% n!m


Nota3
Los atributos los veremos con ms detalle en otra leccin de este
mismo mdulo.


16
El nombre de los miembros de las enumeraciones
Tanto si indicamos o no el atributo )lags a una enumeracin, la podemos usar de
esta forma:
Dim c As Colores = Colores/A&!l 0r Colores/"o#o
Es decir, podemos "sumar" los valores definidos en la enumeracin. Antes de
explicar con detalle que beneficios nos puede traer el uso de este atributo, veamos
una caracterstica de las enumeraciones que no tenamos en VB6.
Como hemos comentado, las enumeraciones son constantes con nombres, pero en
Visual Basic 2005 esta definicin llega ms lejos que en VB6, de hecho, podemos
saber "el nombre" de un valor de una enumeracin, para ello tendremos que usar el
mtodo ToString, (el cual se usa para convertir en una cadena cualquier valor
numrico).
Por ejemplo, si tenemos la siguiente asignacin:
Dim s As String = Colores/A&!l/1oString
La variable s contendr la palabra A4@ulA no el valor 4.
Esto es aplicable a cualquier tipo de enumeracin, se haya o no usado el atributo
)lags*ttribute.
Una vez aclarado este comportamiento de las enumeraciones en Visual Basic 2005,
veamos que es lo que ocurre cuando sumamos valores de enumeraciones a las que
hemos aplicado el atributo )lags y a las que no se lo hemos aplicado. Empecemos
por este ltimo caso.
Si tenemos este cdigo:
n!m Colores As ,-te
"o#o = 1
$er%e = 2
A&!l = .
n% n!m
Dim c As Colores = Colores/A&!l 0r Colores/"o#o
Dim s As String = c/1oString
17
El contenido de la variable s ser A5A, es decir, la representacin numrica del valor
contenido: 4 + 1, ya que el valor de la constante 4@ul es 4 y el de la constante
Bo(o es 1.
Pero si ese mismo cdigo lo usamos de esta forma (aplicando el atributo )lags a la
enumeracin):
()lags()* +
n!m Colores As ,-te
"o#o = 1
$er%e = 2
A&!l = .
n% n!m
Dim c As Colores = Colores/A&!l 0r Colores/"o#o
Dim s As String = c/1oString
El contenido de la variable s ser: ABo(oC 4@ulA, es decir, se asignan los nombres
de los miembros de la enumeracin que intervienen en ese valor, no el valor
"interno".

'os valores de una enumeraci(n no son simples n)meros
Como hemos comentado, los miembros de las enumeraciones realmente son valores
de un tipo de datos entero (en cualquiera de sus variedades) tal como podemos
comprobar en la figura 1.7:
Fi'ura $.D. *os tipos su#%acentes posi#les de una enumeracin
18

Por tanto, podemos pensar que al igual que ocurra en VB6, podemos usar cualquier
valor para asignar a una variable declarada como una enumeracin, al menos si ese
valor est dentro del rango adecuado.
Pero en Visual Basic 2005 esto no es posible, al menos si lo hacemos de forma
"directa" y con 7ption Strict conectado, ya que recibiremos un error indicndonos
que no podemos convertir, por ejemplo, un valor entero en un valor del tipo de la
enumeracin. En la figura 1.8 podemos ver ese error al intentar asignar el valor 3 a
una variable del tipo -olores (definida con el tipo predeterminado Integer).
Fi'ura $.E. Error al asi'nar un valor AnormalA a una varia#le del tipo
-olores

El error nos indica que no podemos realizar esa asignacin, pero el entorno
integrado de Visual Basic Express 2005 tambin nos ofrece alternativas para que
ese error no se produzca, esa ayuda se obtiene pulsando en el signo de admiracin
que tenemos justo donde est el cursor del ratn, pero no solo nos dice cmo
corregirlo, sino que tambin nos da la posibilidad de que el propio IDE se encargue
de corregirlo, tal como podemos apreciar en la figura 1.9.
Fi'ura $.F. 7pciones de correccin de errores
Lo nico que tendramos que hacer es pulsar en la sugerencia de correccin, que en
este caso es la nica que hay, pero en otros casos pueden ser varias las opciones y
tendramos que elegir la que creamos adecuada.
19
El cdigo final (una vez corregido) quedara de la siguiente forma:
Dim c As Colores = C1-2e(3, Colores)
CType es una de las formas que nos ofrece Visual Basic 2005 de hacer conversiones
entre diferentes tipos de datos, en este caso convertimos un valor entero en uno del
tipo -olores.
Si compilamos y ejecutamos la aplicacin, sta funcionar correctamente.
Aunque sabemos que es posible que usando CType no asignemos un valor dentro
del rango permitido. En este caso, el valor 3 podramos darlo por bueno, ya que es
la suma de 1 y 2 (Bo(o y Verde), pero que pasara si el valor asignado es, por
ejemplo, 15? En teora no deberamos permitirlo.
Estas validaciones podemos hacerlas de dos formas:
1- Con la clsica solucin de comprobar el valor indicado con todos los valores
posibles.
2- Usando funciones especficas del tipo %num. Aunque en este ltimo caso, solo
podremos comprobar los valores definidos en la enumeracin.
En el siguiente ejemplo podemos hacer esa comprobacin.
S!b mostrarColor(,-$al c As Colores)
4 com2robar si el 5alor in%ica%o es correcto
4 si no est67 %e8ini%o, !sar el 5alor A&!l
I8 9n!m:/IsDe8ine%(;et1-2e(Colores), c) = )alse 1hen
c = Colores/A&!l
n% I8
Console/<rite'ine("l color es =0>", c)
n% S!b
Este cdigo lo que hace es comprobar si el tipo de datos -olores tiene definido el
valor contenido en la variable c, en caso de que no sea as, usamos un valor
predeterminado.

Nota3
La funcin IsDefined slo comprueba los valores que se han definido
en la enumeracin, no las posibles combinaciones que podemos
conseguir sumando cada uno de sus miembros, incluso aunque
hayamos usado el atributo )lags*ttribute.

20
4rra%s 9matrices:
Los arrays (o matrices) tambin es algo que podamos usar en VB6, si bien la forma
en que se almacena en la memoria y la forma en que podemos usarlas en Visual
Basic 2005 ha cambiado, aunque la forma en que podemos usarlas es idntica a
VB6... o casi.
En Visual Basic 2005 la declaracin de un array la haremos de la misma forma que
en VB6, en el siguiente ejemplo declaramos un array de tipo String llamado
nom#res:
Dim nombres() As String
Al igual que en VB6, podemos indicar el nmero de elementos que contendr el
array:
Dim nombres(10) As String
Tal como ocurre en VB6, al realizar esta declaracin lo que conseguimos es definir
un array de 11 elementos: desde cero hasta 10. Si bien, en VB6 tenemos la
posibilidad de indicar cual era el valor del ndice inferior predeterminado de los
arrays, podemos elegir entre cero y uno mediante la instruccin 7ption Base
indicando a continuacin un 0 o un 1. En Visual Basic 2005 no existe esa
instruccin, es ms en Visual Basic 2005 todos los arrays deben tener como ndice
inferior el valor cero.
Otra posibilidad que tenamos en VB6 era indicar el rango de ndices que podamos
asignar, esto lo logrbamos usando la clusula To al definir un array, por ejemplo:
Dim nombres(10 1o 25) As String
Pero esta declaracin es ilegal en Visual Basic 2005, por el hecho de que los arra%s
de .NET siempre de#en tener el valor cero como ,ndice inferior.
Lo que si podemos hacer en Visual Basic 2005 es usar To para indicar el valor
mximo del ndice, aunque no tiene la misma "potencia" que en VB6, al menos de
esta forma el cdigo resultar ms legible:
Dim nombres(0 1o 10) As String

"eclarar e iniciali*ar un array
Lo que no podemos hacer en VB6 era declarar un array y al mismo tiempo asignarle
valores.
En Visual Basic 2005 esto lo hacemos indicando los valores a asignar justo despus
de la declaracin y encerrndolos entre llaves:
21
Dim nombres() As String = ="?e2e", "@!an", "'!isa">
Con el cdigo anterior estamos creando un array de tipo String con tres valores
cuyos ndices van de cero a dos.
Si el array es bidimensional (o con ms dimensiones), tambin podemos
inicializarlos al declararlo, pero en este caso debemos usar doble juego de llaves:
Dim nombres(,) As String = =="@!an", "?e2e">, ="Ana", "5a">>
En este cdigo tendramos un array bidimensional con los siguientes valores:
nombres(0,0)= Juan
nombres(0,1)= Pepe
nombres(1,0)= Ana
nombres(1,1)= Eva


Cambiar el tama+o de un array
Para cambiar el tamao de un array, al igual que en VB6, usaremos la instruccin
'eDim, pero a diferencia de VB6 no podemos usar 'eDim para definir un array, en
Visual Basic 2005 siempre hay que declarar previamente los arrays antes de
cambiarles el tamao.
Lo que tambin podemos hacer en Visual Basic 2005 es cambiar el tamao de un
array y mantener los valores que tuviera anteriormente, para lograrlo debemos usar
'eDim +resere.
Si bien tanto 'eDim como 'eDim +resere se pueden usar en arrays de cualquier
nmero de dimensiones, en los arrays de ms de una dimensin solamente
podemos cambiar el tamao de la ltima dimensin.


Eliminar el contenido de un array
Una vez que hemos declarado un array y le hemos asignado valores, es posible que
nos interese eliminar esos valores de la memoria, para lograrlo, podemos hacerlo de
tres formas:
1. Redimensionando el array indicando que tiene cero elementos, aunque en el
mejor de los casos, si no estamos trabajando con arrays de ms de una
22
dimensin, tendramos un array de un elemento, ya que, como hemos
comentado anteriormente, los arrays de .NET el ndice inferior es cero.
2. Usar la instruccin %rase. Al igual que en VB6, %rase elimina totalmente el
array de la memoria.
3. Asignar un valor $ot"ing al array. Esto funciona en Visual Basic 2005 pero no
en VB6, debido a que en Visual Basic 2005 los arrays son tipos por referencia.


'os arrays son tipos por referencia
Como acabamos de ver, en Visual Basic 2005 los arrays son tipos por referencia, y
tal como comentamos anteriormente, los tipos por referencia realmente lo que
contienen son una referencia a los datos reales no los datos propiamente dichos.
Cual es el problema?
Vemoslo con un ejemplo y as lo tendremos ms claro.
Dim nombres() As String = ="@!an", "?e2e", "Ana", "5a">
Dim otros() As String
otros = nombres
nombres(0) = "Antonio"
En este ejemplo definimos el array nom#res y le asignamos cuatro valores. A
continuacin definimos otro array llamado otros y le asignamos lo que tiene
nom#res. Por ltimo asignamos un nuevo valor al elemento cero del array
nom#res.
Si mostramos el contenido de ambos arrays nos daremos cuenta de que realmente
solo existe una copia de los datos en la memoria, y tanto nom#res90: como
otros90: contienen el nombre A4ntonioA. En VB6 cada array era independiente del
otro y esa asignacin a nom#res90: no afectaba al valor contenido en otros90:.
Qu ha ocurrido?
Que debido a que los arrays son tipos por referencia, solamente existe una copia de
los datos y tanto la variable nombres como la variable otros lo que contienen es una
referencia (o puntero) a los datos.
Si realmente queremos tener copias independientes, debemos hacer una copia del
array nombres en el array otros, esto es fcil de hacer si usamos el mtodo CopyTo.
23
ste mtodo existe en todos los arrays y nos permite copiar un array en otro
empezando por el ndice que indiquemos.
El nico requisito es que el array de destino debe estar inicializado y tener espacio
suficiente para contener los elementos que queremos copiar.
En el siguiente cdigo de ejemplo hacemos una copia del contenido del array
nom#res en el array otros, de esta forma, el cambio realizado en el elemento cero
de nom#res no afecta al del array otros.
Dim nombres() As String = ="@!an", "?e2e", "Ana", "5a">
Dim otros() As String
"eDim otros(nombres/'ength)
nombres/Co2-1o(otros, 0)
nombres(0) = "Antonio"

Adems del mtodo CopyTo, los arrays tienen otros miembros que nos pueden ser
de utilidad, como por ejemplo la propiedad Lengt" usada en el ejemplo para saber
cuantos elementos tiene el array nom#res.
Para averiguar el nmero de elementos de un array, tambin podemos usar la
funcin ,Bound, que es la que nos serva en Visual Basic 6.0 para saber esa
informacin.
Sin embargo, el uso de la funcin LBound, (que sirve para averiguar el ndice
inferior de un array), no tiene ningn sentido en Visual Basic 2005, ya que todos los
arrays siempre tienen un valor cero como ndice inferior.
Para finalizar este tema, solo nos queda por decir, que los arrays de Visual Basic
2005 realmente son tipos de datos derivados de la clase *rray y por tanto disponen
de todos los miembros definidos en esa clase, aunque de esto hablaremos en la
prxima leccin, en la que tambin tendremos la oportunidad de profundizar un
poco ms en los tipos por referencia y en como podemos definir nuestros propios
tipos de datos, tanto por referencia como por valor.

24
Introduccin
En la leccin anterior vimos los tipos de datos predefinidos en .NET Framework, en
esta leccin veremos cmo podemos crear nuestros propios tipos de datos, tanto
por valor como por referencia.
Tambin tendremos ocasin de ver los distintos niveles de accesibilidad que
podemos aplicar a los tipos, as como a los distintos miembros de esos tipos de
datos. De los distintos miembros que podemos definir en nuestros tipos, nos
centraremos en las propiedades para ver en detalle los cambios que han sufrido con
respecto a VB6. Tambin veremos temas relacionados con la programacin
orientada a objetos (POO) en general y de forma particular los que ataen a las
interfaces.

-lases % estructuras
Clases: Tipos por referencia definidos por el usuario
o Las clases: El corazn de .NET Framework
La herencia: Caracterstica principal de la Programacin
Orientada a Objetos
Encapsulacin y Polimorfismo: Dos viejos conocidos de VB
Object: La clase base de todas las clases de .NET
o Definir una clase
Una clase especial: Module
Los miembros de una clase
Caractersticas de los mtodos y propiedades
Accesibilidad, mbito y miembros compartidos
Parmetros y parmetros opcionales
Array de parmetros opcionales (ParamArray)
Sobrecarga de mtodos y propiedades
Parmetros por valor y parmetros por referencia
o Instanciar: Crear un objeto en la memoria
Declarar y asignar en un solo paso
El constructor: El punto de inicio de una clase
Constructores parametrizados
Cuando Visual Basic 2005 no crea un constructor
automticamente
El destructor: El punto final de la vida de una clase
Estructuras: Tipos por valor definidos por el usuario
o Definir una estructura
o Constructores de las estructuras
o Destructores de las estructuras
o Los miembros de una estructura
o Cmo usar las estructuras
25
Accesibilidad y &mbito
o mbito
mbito de bloque
mbito de procedimiento
mbito de mdulo
mbito de espacio de nombres
o La palabra clave Global
o Accesibilidad
Accesibilidad de las variables en los procedimientos
o Las accesibilidades predeterminadas
o Anidacin de tipos
Los tipos anidables
El nombre completo de un tipo
Importacin de espacios de nombres
Alias de espacios de nombres
,ropiedades
o Definir una propiedad
o Propiedades de solo lectura
o Propiedades de solo escritura
o Diferente accesibilidad para los bloques Get y Set
o Propiedades predeterminadas
Sobrecarga de propiedades predeterminadas
-nterfaces
o Qu es una interfaz?
o Qu contiene una interfaz?
o Una interfaz es un contrato
o Las interfaces y el polimorfismo
o Usar una interfaz en una clase
o Acceder a los miembros implementados
o Saber si un objeto implementa una interfaz
o Implementacin de mltiples interfaces
o Mltiple implementacin de un mismo miembro
o Dnde podemos implementar las interfaces?
o Un ejemplo prctico usando una interfaz de .NET

-lases3 Tipos por referencia definidos por el usuario
Tal como vimos en la leccin anterior, los tipos de datos se dividen en dos grupos:
tipos por valor y tipos por referencia. Los tipos por referencia realmente son clases,
de la cuales debemos crear una instancia para poder usarlas, esa instancia o copia,
se crea siempre en la memoria lejana ("eap) y las variables lo nico que contienen
es una referencia a la direccin de memoria en la que el CLR (Common Language
'untime, motor en tiempo de ejecucin de .NET), ha almacenado el objeto recin
creado.
26
Al igual que ocurre en VB6, tambin podemos crear nuestras propias clases en
Visual Basic 2005, aunque como veremos tanto la forma de definirlas como de
instanciarlas ha cambiado un poco. Aunque ese cambio es solo, digamos, en la
forma, ya que en el fondo es lo mismo, siempre salvando las distancias, ya que
como veremos, las clases de Visual Basic 2005 pueden llegar a ser mucho ms
verstiles e incluso potentes que las de VB6.
Antes de entrar en detalles sintcticos, veamos la importancia que tienen las clases
en .NET Framework y como repercuten en las que podamos definir nosotros usando
Visual Basic 2005.

*as clases3 el cora@n de .NET Frameor!
Prcticamente todo lo que podemos hacer en .NET Framework lo hacemos mediante
clases. La librera de clases de .NET Framework es precisamente el corazn del
propio .NET, en esa librera de clases est todo lo que podemos hacer dentro de
este marco de programacin; para prcticamente cualquier tarea que queramos
realizar existen clases, y si no existen, las podemos definir nosotros mismos, bien
ampliando la funcionalidad de alguna clase existente mediante la herencia, bien
implementando algn tipo de funcionalidad previamente definida o simplemente
crendolas desde cero.

'a #erencia: Caracter!stica principal de la ,rogramaci(n $rientada a
$betos
El concepto de Programacin Orientada a Objetos (POO) es algo intrnsico al
propio .NET Framework, por tanto es una caracterstica que todos los lenguajes
basados en este "marco de trabajo" tienen de forma predeterminada, entre ellos el
Visual Basic 2005. De las caractersticas principales de la POO tenemos que
destacar la herencia, que en breve podemos definir como una caracterstica que nos
permite ampliar la funcionalidad de una clase existente sin perder la que ya tuviera
previamente. Gracias a la herencia, podemos crear una nueva clase que se derive
de otra, esta nueva clase puede cambiar el comportamiento de la clase base y/o
ampliarlo, de esta forma podemos adaptar la clase, llammosla, original para
adaptarla a nuestras necesidades.
El tipo de herencia que .NET Framework soporta es la herencia simple, es decir, solo
podemos usar una clase como base de la nueva, si bien, como veremos ms
adelante, podemos agregar mltiple funcionalidad a nuestra nueva clase. Esta
funcionalidad nos servir para aprovechar la funcionalidad de muchas de las clases
existentes en .NET Framework, funcionalidad que solamente podremos aplicar si
previamente hemos firmado un contrato que asegure a la clase de .NET que la
nuestra est preparada para soportar esa funcionalidad, esto lo veremos dentro de
poco con ms detalle.

27
Encapsulaci(n y ,olimorfismo: "os vieos conocidos de V.
La encapsulacin y el polimorfismo son otras dos caractersticas de la programacin
orientada a objetos. Aunque estas dos no nos resultarn desconocidas, ya que
desde la versin 5.0 de Visual Basic estaban a nuestra disposicin.
La encapsulacin nos permite abstraer la forma que tiene de actuar una clase sobre
los datos que contiene o manipula, para poder lograrlo se exponen como parte de la
clase los mtodos y propiedades necesarios para que podamos manejar esos datos
sin tener que preocuparnos cmo se realiza dicha manipulacin.
El polimorfismo es una caracterstica que nos permite realizar ciertas acciones o
acceder a la informacin de los datos contenidos en una clase de forma semi-
annima, al menos en el sentido de que no tenemos porqu saber sobre que tipo
objeto realizamos la accin, ya que lo nico que nos debe preocupar es que
podemos hacerlo, por la sencilla razn de que estamos usando ciertos mecanismos
que siguen unas normas que estn adoptadas por la clase.
El ejemplo clsico del polimorfismo es que si tengo un objeto que "sabe" cmo
morder, da igual que lo aplique a un ratn o a un dinosaurio, siempre y cuando esas
dos "clases" expongan un mtodo que pueda realizar esa accin... y como deca la
documentacin de Visual Basic 5.0, siempre ser preferible que nos muerda un
ratn antes que un dinosaurio.

$bect: 'a clase base de todas las clases de .NET
Todas las clases de .NET se derivan de la clase Object, es decir, lo indiquemos o no,
cualquier clase que definamos tendr el comportamiento heredado de esa clase. El
uso de la clase Object como base del resto de las clases de .NET es la nica
excepcin a la herencia simple soportada por .NET, ya que de forma implcita, todas
las clases de .NET se derivan de la clase Object independientemente de que estn
derivadas de cualquier otra.
Esta caracterstica nos asegura que siempre podremos usar un objeto del tipo
Object para acceder a cualquier clase de .NET, aunque no debemos abrumarnos
todava, ya que en el texto que sigue veremos con ms detalle que significado tiene
esta afirmacin.
De los miembros que tiene la clase Object debemos resaltar el mtodo ToString, el
cual ya lo vimos en la leccin anterior cuando queramos convertir un tipo primitivo
en una cadena. Este mtodo est pensado para devolver una representacin en
formato cadena de un objeto. El valor que obtengamos al usar este mtodo
depender de cmo est definido en cada clase y por defecto lo que devuelve es el
nombre completo de la clase, si bien en la mayora de los casos el valor que
obtendremos al usar este mtodo debera ser ms intuitivo, por ejemplo los tipos de
datos primitivos tienen definido este mtodo para devuelva el valor que contienen,
de igual forma, nuestras clases tambin deberan devolver un valor adecuado al
contenido almacenado. De cmo hacerlo, nos ocuparemos en breve.

28
Nota3
Todos los tipos de datos de .NET, ya sean por valor o por referencia
siempre estn derivados de la clase Object, por tanto podremos llamar
a cualquiera de los mtodos que estn definidos en esa clase.
Aunque en el caso de los tipos de datos por valor, cuando queremos
acceder a la clase Object que contienen, .NET Framework primero
debe convertirla en un objeto por referencia (boxing) y cuando hemos
dejado de usarla y queremos volver a asignar el dato a la variable por
valor, tiene que volver a hacer la conversin inversa (unboxing).

/efinir una clase
En Visual Basic 6.0, cada vez que definimos una clase tenemos que agregar al
proyecto un fichero con extensin .cls, y a partir de ese momento, todo el cdigo
escrito en ese fichero formaba parte de la clase. En Visual Basic 2005 esto ha
cambiado, y aunque lo habitual es que usemos un fichero independiente para cada
clase que escribamos, esto solo es algo opcional, en principio porque en VB2005
solo existe un tipo de fichero para escribir el cdigo: un fichero con extensin .v#,
en el que podemos escribir una clase o cualquiera de los tipos que el lenguaje nos
permite.

Nota3
En Visual Basic 2005 cualquier cdigo que queramos escribir estar
dentro de una clase.

En Visual Basic 2005 las clases se definen usando la palabra clave Class seguida del
nombre de la clase, esa definicin acaba indicndolo con %nd Class.
En el siguiente ejemplo definimos una clase llamada Cliente que tiene dos campos
pblicos.
Class Cliente
?!blic Aombre As String
?!blic A2elli%os As String
n% Class
Una vez definida la clase podemos agregar los elementos (o miembros) que
creamos conveniente.
En el ejemplo anterior, para simplificar, hemos agregado dos campos pblicos,
aunque tambin podramos haber definido cualquiera de los miembros permitidos
en las clases.
29


Gna clase especial3 Module
En Visual Basic 2005 tambin podemos definir una clase especial llamada Module,
este tipo de clase tiene un tratamiento especial y es el equivalente a los mdulos
B4S de VB6.
La definicin se hace usando la instruccin (odule seguida del nombre a usar y
acaba con %nd (odule.
Cualquier miembro definido en un (odule siempre estar accesible en todo el
proyecto y para usarlos no tendremos que crear ningn objeto en memoria.
Las clases definidas con la palabra clave (odule realmente equivalen a las clases en
las que todos los miembros estn compartidos y por tanto siempre disponibles a
toda la aplicacin.
De todos estos conceptos nos ocuparemos en las siguientes lecciones, pero es
necesario explicar que existe este tipo de clase ya que ser el tipo de datos que el
IDE de Visual Basic 2005 usar al crear aplicaciones del tipo consola, ya que ese
ser el tipo de proyecto que crearemos para practicar con el cdigo mostrado en
este primer mdulo.


*os miem#ros de una clase
Una clase puede contener cualquiera de estos elementos (miembros):
Enumeraciones
Campos
Mtodos (funciones o procedimientos)
Propiedades
Eventos
*as enumeraciones, como vimos en la leccin anterior, podemos usarlas para
definir valores constantes relacionados, por ejemplo para indicar los valores posibles
de cualquier "caracterstica" de la clase.
*os campos son variables usadas para mantener los datos que la clase manipular.
*os mHtodos son las acciones que la clase puede realizar, normalmente esas
acciones sern sobre los datos que contiene. Dependiendo de que el mtodo
devuelva o no un valor, podemos usar mtodos de tipo )unction o de tipo Sub
respectivamente.
30
*as propiedades son las "caractersticas" de las clases y la forma de acceder
"pblicamente" a los datos que contiene. Por ejemplo, podemos considerar que el
nombre y los apellidos de un cliente son dos caractersticas del cliente.
*os eventos son mensajes que la clase puede enviar para informar que algo est
ocurriendo en la clase.


-aracter,sticas de los mHtodos % propiedades

Accesibilidad/ &mbito y miembros compartidos
Aunque estos temas los veremos en breve con ms detalle, para poder comprender
mejor las caractersticas de los miembros de una clase (o cualquier tipo que
definamos), daremos un pequeo adelanto sobre estas caractersticas que podemos
aplicar a los elementos que definamos.
Accesibilidad y mbito son dos conceptos que estn estrechamente relacionados.
Aunque en la prctica tienen el mismo significado, ya que lo que representan es la
"cobertura" o alcance que tienen los miembros de las clases e incluso de las mismas
clases que definamos.
Si bien cada uno de ellos tienen su propia "semntica", tal como podemos ver a
continuacin:
mbito
Es el alcance que la definicin de un miembro o tipo puede tener. Es decir, cmo
podemos acceder a ese elemento y desde dnde podemos accederlo.
El mbito de un elemento de cdigo est restringido por el "sitio" en el que lo
hemos declarado. Estos sitios pueden ser:
Im#ito de #lo&ue3 Disponible nicamente en el bloque de cdigo en el que
se ha declarado.
Im#ito de procedimiento3 Disponible nicamente dentro del procedimiento
en el que se ha declarado.
Im#ito de mdulo3 Disponible en todo el cdigo del mdulo, la clase o la
estructura donde se ha declarado.
Im#ito de espacio de nom#res3 Disponible en todo el cdigo del espacio
de nombres.

31
Accesibilidad
A los distintos elementos de nuestro cdigo (ya sean clases o miembros de las
clases) podemos darle diferentes tipos de accesibilidad. Estos tipos de "acceso"
dependern del mbito que queramos que tengan, es decir, desde dnde podremos
accederlos.
Los modificadores de accesibilidad son:
8u#lic3 Acceso no restringido.
8rotected3 Acceso limitado a la clase contenedora o a los tipos derivados de
esta clase.
Friend3 Acceso limitado al proyecto actual.
8rotected Friend3 Acceso limitado al proyecto actual o a los tipos derivados
de la clase contenedora.
8rivate3 Acceso limitado al tipo contenedor.
Por ejemplo, podemos declarar miembros privados a una clase, en ese caso, dichos
miembros solamente los podremos acceder desde la propia clase, pero no desde
fuera de ella.

Nota3
Al igual que ocurre en VB6, al declarar una variable con Dim, por regla
general, el mbito que le estamos aplicando es privado, pero como
veremos, en Visual Basic 2005, dependiendo del tipo en el que
declaremos esa variable, el mbito puede ser diferente a privado.

Miembros compartidos
Por otro lado, los miembros compartidos de una clase o tipo, son elementos que no
pertenecen a una instancia o copia en memoria particular, sino que pertenecen al
propio tipo y por tanto siempre estn accesibles o disponibles, dentro del nivel del
mbito y accesibilidad que les hayamos aplicado, y su tiempo de ida es el mismo
que el de la aplicacin.

Nota3
Lo ms parecido en VB6 a los miembros compartidos de Visual Basic
2005 son los mtodos y campos declarados en un mdulo .BAS.

Del mbito, la accesibilidad y los miembros compartidos nos ocuparemos con ms
detalle en una leccin posterior, donde veremos ciertas peculiaridades, como puede
32
ser la limitacin del mbito de un miembro que aparentemente tiene una
accesibilidad no restringida.


,ar&metros y par&metros opcionales
En Visual Basic 2005, tanto los miembros de una clase, (funciones y mtodos Sub),
como las propiedades pueden recibir parmetros. Esto no es algo nuevo, ya que en
VB6 podamos tener parmetros en estos tipos de miembros (o elementos) de una
clase, adems se siguen soportando tanto los parmetros opcionales (Optional)
como los arrays de parmetros (+aram*rray).
Con los parmetros opcionales lo que conseguimos es permitir que el usuario no
tenga que introducir todos los parmetros, sino solo los que realmente necesite, del
resto, (los no especificados), se usar el valor predeterminado que hayamos
indicado, ya que una de las "restricciones" de este tipo de parmetros con respecto
a VB6 es que siempre que indiquemos un parmetro opcional, debemos indicar
tambin el valor por defecto que debemos usar en caso de que no se especifique.
Esto realmente sigue funcionando igual que en VB6 cuando al parmetro opcional le
indicamos el tipo de datos. Lo que Visual Basic 2005 no permite es definir un
parmetro opcional de tipo #ariant, entre otras cosas, porque ese tipo de datos no
existe en VB2005.
Veamos unos ejemplo para aclarar nuestras ideas:
)!nction S!ma(n1 As Integer, 02tional n2 As Integer = 15) As
Integer
S!ma = n1 B n2
n% )!nction
En este primer ejemplo, el primer parmetro es obligatorio (siempre debemos
indicarlo) y el segundo es opcional, si no se indica al llamar a esta funcin, se usar
el valor 15 que es el predeterminado.
Para llamar a esta funcin, lo podemos hacer de estas tres formas:
4 1C in%ican%o los %os 2ar6metros (el res!lta%o ser6 .= 1 B 3)
t = S!ma(1, 3)
4 2C In%ican%o solamente el 2rimer 2ar6metro (el res!lta%o ser6
16= 1 B 15)
t = S!ma(1)
4 3C In%ican%o los %os 2ar6metros, 2ero en el o2cional !samos el
nombre
33
t = S!ma(1, n2D= E)
El tercer ejemplo solamente tiene utilidad si hay ms de un parmetro opcional.

Nota3
Los parmetros opcionales deben aparecer en la lista de parmetros
del mtodo, despus de los "obligatorios"


Array de par&metros opcionales (,aramArray)
En cuanto al uso de +aram*rray, este tipo de parmetro opcional nos permite
indicar un nmero indeterminado de parmetros, aunque el funcionamiento con
respecto a VB6 es algo diferente, en Visual Basic 2005 siempre debe ser una array
de un tipo especfico e internamente se trata como un array normal y corriente, es
decir, dentro del mtodo o propiedad se accede a l como si de un array se
tratara... entre otras cosas, porque es un array!
En VB6 no siempre era as y algunas veces tenamos verdaderos problemas al
acceder a esos datos, por suerte, en Visual Basic 2005 el uso de los parmetros
opcionales con +aram*rray es ms simple e intuitivo, aunque a algunos puede que
le parezca menos "potente", ya que en VB6, cualquiera de los parmetros poda ser
a su vez un array. Pero en Visual Basic 2005, al menos si tenemos activado Option
Strict, esto no es posible, ya que solo aceptar los parmetros del tipo indicado.
Veamos lo que VB6 permite y cmo hacerlo en VB2005:
)!nction S!ma(?aramArra- n() As $ariant) As 'ong
Dim total As 'ong
Dim i As 'ong
Dim # As 'ong
4
)or i = 0 1o F,o!n%(n)
I8 IsArra-(n(i)) 1hen
)or # = ',o!n%(n(i)) 1o F,o!n%(n(i))
total = total B n(i)(#)
AeGt
34
lse
total = total B n(i)
n% I8
AeGt
S!ma = total
n% )!nction
4 ?ara !sarloD
Dim t As 'ong
Dim a(2) As 'ong
a(0) = 1D a(1) = 2D a(2) = 3
t = S!ma(a, ., 5, 6)
Hsg,oG(t)

Para usar este cdigo en Visual Basic 2005 tendremos que desactivar Option Strict y
cambiar el tipo #ariant por Object, (cosa que el IDE har automticamente si
pegamos el cdigo), lo dems se puede quedar igual, incluso los tipos de datos,
aunque debemos recordar que un Long de VB6 es un Integer de VB2005.
Pero como no debemos "acostumbrarnos" a desactivar Option Strict, vamos a ver el
cdigo "bueno" de Visual Basic 2005, aunque no nos permita usar un array en los
parmetros al llamar a la funcin.
)!nction S!ma(,-$al ?aramArra- n() As Integer) As Integer
Dim total As Integer
)or i As Integer = 0 1o n/'ength C 1
total B= CInt(n(i))
AeGt
"et!rn total
n% )!nction
35
4 ?ara !sarloD
Dim t As Integer = S!ma(1, 2, 3, ., 5, 6)
4
Hsg,oG(t)
Aqu vemos el nuevo "look & feel" de Visual Basic 2005:
- Usamos 'eturn para devolver el valor en lugar de usar el nombre de la funcin,
aunque se sigue soportando.
- Podemos inicializar la variable a usar con el bucle )or, esto lo veremos con ms
detalle cuando tratemos la accesibilidad.
- Usamos propiedades para saber la cantidad de elementos del array.
- Comprobamos que en Visual Basic 2005 tenemos otra forma de incrementar el
contenido de una variable: t B= CInt(n(i)) es lo mismo que t = t B
CInt(n(i)), que aunque parezca un snobismo, realmente ahorra algn ciclo de
reloj.

Nota3
Cuando queramos usar ParamArray para recibir un array de
parmetros opcionales, esta instruccin debe ser la ltima de la lista
de parmetros de la funcin (mtodo).
Tampoco se permite tener parmetros opcionales y ParamArray en la
misma funcin.


Sobrecarga de m0todos y propiedades
La sobrecarga de funciones (realmente de mtodos y propiedades), es una
caracterstica que nos permite tener una misma funcin con diferentes tipos de
parmetros, ya sea en nmero o en tipo.
Aunque nos pueda parecer que la sobrecarga de mtodos la podemos "simular" en
VB6 con los parmetros opcionales, realmente no es lo mismo. Ahora veremos
porqu.
Supongamos que queremos tener dos funciones (o ms) que nos permitan hacer
operaciones con diferentes tipos de datos, y que, segn el tipo de datos usado, el
valor que devuelva sea de ese mismo tipo. En VB6 es imposible hacer esto. Salvo
que creemos dos funciones con nombres diferentes, pero en ese caso ya no
estaremos usando la sobrecarga.
36
En este ejemplo, tenemos dos funciones que se llaman igual pero una recibe valores
de tipo entero y la otra de tipo decimal:
)!nction S!ma(n1 As Integer, n2 As Integer) As Integer
"et!rn n1 B n2
n% )!nction
)!nction S!ma(n1 As Do!ble, n2 As Do!ble) As Do!ble
"et!rn n1 B n2
n% )!nction
Como podemos comprobar las dos funciones tienen el mismo nombre, pero tanto
una como otra reciben parmetros de tipos diferentes.
Con Visual Basic 2005 podemos sobrecargar funciones, pero lo interesante no es
que podamos hacerlo, sino cmo podemos usar esas funciones. En el cdigo
anterior tenemos dos funciones llamadas Suma, la primera acepta dos parmetros
de tipo Integer y la segunda de tipo Double. Lo interesante es que cuando
queramos usarlas, no tenemos que preocuparnos de cual vamos a usar, ya que ser
el compilador el que decida la ms adecuada al cdigo que usemos, por ejemplo:
4 n este caso, se !sar6 la I!e recibe %os 5alores enteros
Hsg,oG( S!ma(10, 22) )
4 n este caso se !sar6 la I!e recibe 5alores %e ti2o Do!ble
Hsg,oG( S!ma(10/5, 22)
El compilador de Visual Basic 2005 es el que decide que funcin usar, esa decisin la
toma a partir de los tipos de parmetros que hayamos indicado. En el segundo
ejemplo de uso, el que mejor coincide es el de los dos parmetros de tipo Double.
Tambin podemos tener sobrecarga usando una cantidad diferente de parmetros,
aunque stos sean del mismo tipo. Por ejemplo, podemos aadir esta declaracin al
cdigo anterior sin que exista ningn tipo de error, ya que esta nueva funcin recibe
tres parmetros en lugar de dos:
)!nction S!ma(n1 As Integer, n2 As Integer, n3 As Integer) As
Integer
"et!rn n1 B n2 B n3
n% )!nction
37
Por tanto, cuando el compilador se encuentre con una llamada a la funcin Suma
en la que se usen tres parmetros, intentar usar esta ltima.

Nota3
Para que exista sobrecarga, la diferencia debe estar en el nmero o en
el tipo de los parmetros, no en el tipo del valor devuelto.

Cuando, desde el IDE de Visual Basic 2005, queremos usar los mtodos
sobrecargados, nos mostrar una lista de opciones indicndonos las posibilidades de
sobrecarga que existen y entre las que podemos elegir, tal como vemos en la figura
1.10:

Fi'ura $.$0. *ista de par.metros soportados por un mHtodo

Tal como comentbamos hace unas lneas, en VB6 se puede simular la sobrecarga
mediante los parmetros opcionales, aunque realmente no es lo mismo. Pero esa
"simulacin" nos viene como anillo al dedo para dar un consejo o advertencia:
J-uidado con las funciones &ue reci#en par.metros opcionalesC %a &ue el
compilador puede producir un error si esa funcin entra en conflicto con
otra Aso#recar'adaAK
Mejor lo vemos con un ejemplo:
)!nction S!ma(n1 As Integer, 02tional n2 As Integer = 33) As
Integer
"et!rn n1 B n2
n% )!nction
Si tenemos esta declaracin adems de las anteriores, el programa no compilar, ya
que si hacemos una llamada a la funcin Suma con dos parmetros enteros, el
compilador no sabr si usar esta ltima o la primera que declaramos, por tanto
producir un error.
38


,ar&metros por valor y par&metros por referencia
Al igual que tenemos dos tipos de datos diferentes, en los parmetros de las
funciones tambin podemos tenerlos, esto tampoco es una novedad de Visual Basic
2005, ya que en VB6 tambin podemos usar By#al o By'ef para indicar al
compilador cmo debe tratar a los parmetros.
Cuando un parmetro es por valor (By#al), el runtime antes de llamar a la funcin
hace una copia de ese parmetro y pasa la copia a la funcin, por tanto cualquier
cambio que hagamos a ese parmetro dentro de la funcin no afectar al valor
usado "externamente".
En el caso de que el parmetro sea por referencia (By'ef), el compilador pasa una
referencia que apunta a la direccin de memoria en la que estn los datos, por
tanto si realizamos cambios dentro de la funcin, ese cambio si que se ver
reflejado en el parmetro usado al llamar a la funcin.

Nota3
Hay que tener en cuenta que si pasamos un objeto a una funcin, da
igual que lo declaremos por valor o por referencia, ya que en ambos
casos se pasa una referencia a la direccin de memoria en la que estn
los datos, porque, como sabemos, las variables de los tipos por
referencia siempre contienen una referencia a los datos, no los datos
en s.

Hasta aqu todo como en VB6.
Lo que cambia en Visual Basic 2005 es que ahora los parmetros en los que no se
indique si es por valor (By#al) o por referencia (By'ef), sern tratados como
parmetros por valor. En VB6 era al revs.

Nota3
Si usamos el IDE de Visual Basic 2005 Express para escribir el cdigo,
no debemos preocuparnos de este detalle, ya que si no indicamos si es
por valor o por referencia, automticamente le aadir la palabra clave
ByVal, para que no haya ningn tipo de dudas.

39
Instanciar3 -rear un o#(eto en la memoria
Una vez que tenemos una clase definida, lo nico de lo que disponemos es de una
especie de plantilla o molde a partir del cual podemos crear objetos en memoria.
La forma de crear esos objetos en Visual Basic 2005 no ha cambiado con respecto al
VB6, salvo en pequeos detalles, veamos algunos ejemplos y as aclararemos esas
diferencias, que por otro lado son importantes.
Lo primero que tenemos que hacer es declarar una variable del tipo que queremos
instanciar, esto lo hacemos usando la instruccin Dim:
Dim c As Cliente
Con esta lnea de cdigo lo que estamos indicando al Visual Basic es que tenemos
intencin de usar una variable llamada c para acceder a una clase de tipo -liente.
Esa variable, cuando llegue el momento de usarla, sabr todo lo que hay que saber
sobre una clase Cliente, pero hasta que no tenga una "referencia" a un objeto de
ese tipo no podremos usarla.
La asignacin de una referencia a un objeto -liente podemos hacerla de dos
formas distintas:
La primera es creando un nuevo objeto en la memoria:
c = AeJ Cliente

Nota3
En VB6 esta forma de crear un nuevo objeto producira un error, ya
que para "asignar" a una variable un nuevo objeto tenemos que usar
la instruccin Set, en Visual Basic 2005 ya no es necesario el uso de
esa instruccin, de hecho si la usamos, recibiremos un error.

A partir de este momento, la variable c tiene acceso a un nuevo objeto del tipo
-liente, por tanto podremos usarla para asignarle valores y usar cualquiera de los
miembros que ese tipo de datos contenga:
c/Aombre = "Antonio"
c/A2elli%os = ""!i& "o%rKg!e&"


40
"eclarar y asignar en un solo paso
Con las clases o tipos por referencia tambin podemos declarar una variable y al
mismo tiempo asignarle un nuevo objeto, esto tampoco es una novedad, aunque s
lo es la forma de comportarse. Veamos primero cmo hacerlo y despus entraremos
en detalles.
Dim c As AeJ Cliente
O tambin:
Dim c As Cliente = AeJ Cliente
Las dos formas producen el mismo resultado, por tanto es recomendable usar la
primera.
En VB6 este tipo de declaracin y asignacin no era recomendable, ya que aade
trabajo extra al compilador de VB. Ese trabajo extra consiste en comprobar si el
objeto al que queremos acceder ya est creado, en caso de que no sea as, primero
lo crea y despus lo usa, el inconveniente es que todas estas comprobaciones las
realiza cada vez que usemos la variable!
En Visual Basic 2005 este comportamiento ya no es as, el objeto se crea en la
memoria y se asigna a la variable, a partir de ese momento no se comprueba si ya
est creado o no, ya que se supone que s est creado.
Lo que debemos tener muy presente es que adems de la sobrecarga de trabajo
que aade VB6 a este tipo de instanciacin, el comportamiento es muy diferente al
de Visual Basic 2005. Por ejemplo, si en VB6 asignamos un valor nulo a una variable
declarada de esta forma y acto seguido usamos la variable, el motor en tiempo de
ejecucin (runtime) crea un nuevo objeto y asunto arreglado. Pero en Visual Basic
2005, si asignamos un valor nulo a una variable, le estamos diciendo al CLR (el
runtime de .NET) que ya no queremos usar ms ese objeto, por tanto lo elimina de
la memoria; si despus queremos volver a usar la variable, debemos crear otro
objeto, (con $e!), de no hacerlo, se producir un error, ya que en Visual Basic 2005
no existe la auto-instanciacin.


El constructor: El punto de inicio de una clase
Cada vez que creamos un nuevo objeto en memoria estamos llamando al
constructor de la clase. En VB6 el constructor es el mtodo Class-Initiali.e. Sin
embargo en Visual Basic 2005 el constructor es un mtodo de tipo Sub llamado
$e!.
En el constructor de una clase podemos incluir el cdigo que creamos conveniente,
pero realmente solamente deberamos incluir el que realice algn tipo de
inicializacin, en caso de que no necesitemos realizar ningn tipo de inicializacin,
41
no es necesario definir el constructor, ya que el propio compilador lo har por
nosotros. Esto es as porque todas las clases deben implementar un constructor, por
tanto si nosotros no lo definimos, lo har el compilador de Visual Basic 2005.
Si nuestra clase -liente tiene un campo para almacenar la fecha de creacin del
objeto podemos hacer algo como esto:
Class Cliente
?!blic Aombre As String
?!blic A2elli%os As String
?!blic )echaCreacion As Date
4
?!blic S!b AeJ()
)echaCreacion = Date/AoJ
n% S!b
n% Class

De esta forma podemos crear un nuevo -liente y acto seguido comprobar el valor
del campo Fec?a-reacion para saber la fecha de creacin del objeto.
En los constructores tambin podemos hacer las inicializaciones que, por ejemplo
permitan a la clase a conectarse con una base de datos, abrir un fichero o cargar
una imagen grfica, etc., aunque en algunos de estos casos nos facilitar la tarea
una nueva caracterstica que VB6 no tiene.


Constructores parametri*ados
De la misma forma que podemos tener mtodos y propiedades sobrecargadas,
tambin podemos tener constructores sobrecargados, ya que debemos recordar que
en Visual Basic 2005, un constructor realmente es un mtodo de tipo Sub, y como
todos los mtodos y propiedades de Visual Basic 2005, tambin admite la
sobrecarga.
La ventaja de tener constructores que admitan parmetros es que podemos crear
nuevos objetos indicando algn parmetro, por ejemplo un fichero a abrir o, en el
caso de la clase -liente, podemos indicar el nombre y apellidos del cliente o
cualquier otro dato que creamos conveniente.
42
Para comprobarlo, podemos ampliar la clase definida anteriormente para que
tambin acepte la creacin de nuevos objetos indicando el nombre y los apellidos
del cliente.
Class Cliente
?!blic Aombre As String
?!blic A2elli%os As String
?!blic )echaCreacion As Date
4
?!blic S!b AeJ()
)echaCreacion = Date/AoJ
n% S!b
4
?!blic S!b AeJ(elAombre As String, losA2elli%os As String)
Aombre = elAombre
A2elli%os = losA2elli%os
)echaCreacion = Date/AoJ
n% S!b
n% Class
Teniendo esta declaracin de la clase -liente, podemos crear nuevos clientes de
dos formas:
Dim c1 As AeJ Cliente
Dim c2 As AeJ Cliente("@ose", "S6nche&")
Como podemos comprobar, en ciertos casos es ms intuitiva la segunda forma de
crear objetos del tipo -liente, adems de que as nos ahorramos de tener que
asignar individualmente los campos Nom#re y 4pellidos.
Esta declaracin de la clase Cliente la podramos haber hecho de una forma
diferente. Por un lado tenemos un constructor "normal" (no recibe parmetros) en
el que asignamos la fecha de creacin y por otro el constructor que recibe los datos
del nombre y apellidos. En ese segundo constructor tambin asignamos la fecha de
creacin, ya que, se instancie como se instancie la clase, nos interesa saber siempre
la fecha de creacin. En este ejemplo, por su simpleza no es realmente un problema
repetir la asignacin de la fecha, pero si en lugar de una inicializacin necesitramos
43
hacer varias, la verdad es que nos encontraramos con mucha "duplicidad" de
cdigo. Por tanto, en lugar de asignar los datos en dos lugares diferentes, podemos
hacer esto otro:
Class Cliente
?!blic Aombre As String
?!blic A2elli%os As String
?!blic )echaCreacion As Date
4
?!blic S!b AeJ()
)echaCreacion = Date/AoJ
n% S!b
4
?!blic S!b AeJ(elAombre As String, losA2elli%os As String)
AeJ()
Aombre = elAombre
A2elli%os = losA2elli%os
n% S!b
n% Class
Es decir, desde el constructor con argumentos llamamos al constructor que no los
tiene, consiguiendo que tambin se asigne la fecha.
Esta declaracin de la clase -liente realmente no compilar. Y no compila por la
razn tan "simple" de que aqu el compilador de Visual Basic 2005 no sabe cual es
nuestra intencin, ya que $e! es una palabra reservada que sirve para crear
nuevos objetos y, siempre, una instruccin tiene preferencia sobre el nombre de un
mtodo, por tanto, podemos recurrir al objeto especial Me el cual nos sirve, al igual
que en VB6, para representar al objeto que actualmente est en la memoria, as
que, para que esa declaracin de la clase Cliente funcione, debemos usar (e.$e!/0
para llamar al constructor sin parmetros.

Nota3
El IDE de Visual Basic 2005 colorea las instrucciones y tipos propios
del lenguaje, tal y como lo hace el de VB6, en el caso de Me, VB6 no la
colorea, pero este no es el motivo de esta nota, lo que no debe
confundirnos es que cuando declaramos Sub New, tanto Sub como
44
New se muestran coloreadas, cuando solo se debera colorear Sub; sin
embargo cuando usamos Me.New, solo se colorea Me y no New que es
correcto, tal como vemos en la figura 1.11, ya que en este caso New
es el nombre de un procedimiento y los procedimientos no son parte
de las instrucciones y tipos de .NET.

Fi'ura $.$$. -oloreo errneo de Ne


Cuando Visual .asic 1223 no crea un constructor autom&ticamente
Tal como hemos comentado, si nosotros no definimos un constructor (Sub $e!), lo
har el propio compilador de Visual Basic 2005, y cuando lo hace automticamente,
siempre es un constructor sin parmetros.
Pero hay ocasiones en las que nos puede interesar que no exista un constructor sin
parmetros, por ejemplo, podemos crear una clase -liente que solo se pueda
instanciar si le pasamos, por ejemplo el nmero de identificacin fiscal, (NIF), en
caso de que no se indique ese dato, no podremos crear un nuevo objeto Cliente, de
esta forma, nos aseguramos siempre de que el NIF siempre est especificado.
Seguramente por ese motivo, si nosotros definimos un constructor con parmetros,
Visual Basic 2005 no crea uno automticamente sin parmetros. Por tanto, si
definimos un constructor con parmetros en una clase y queremos que tambin
tenga uno sin parmetros, lo tenemos que definir nosotros mismos.


El destructor: El punto final de la vida de una clase
De la misma forma que una clase tiene su punto de entrada o momento de
nacimiento en el constructor, tambin tienen un sitio que se ejecutar cuando el
45
objeto creado en la memoria ya no sea necesario, es decir, cuando acabe la vida del
objeto creado.
El destructor de Visual Basic 2005 es un mtodo llamado )inali.e, el cual se hereda
de la clase Object, por tanto no es necesario que escribamos nada en l. El propio
CLR se encargar de llamar a ese mtodo cuando el objeto ya no sea necesario. En
VB6, el destructor es el mtodo Class-Terminate.
La principal diferencia con VB6 en lo referente a la forma en que se destruyen los
objetos, es que en VB6 si a un objeto le asignamos un valor nulo ($ot"ing) el
destructor se ejecuta inmediatamente y el objeto se elimina de la memoria, pero en
.NET la forma en que se destruyen los objetos es diferente, nunca podremos tener
la certeza de cuando se destruye, incluso si le asignamos un valor nulo. Esto es as
debido a que en .NET los objetos no se destruyen inmediatamente y existe un
"sistema" que se encarga de realizar esta gestin de limpieza: El recolector de
basura o de objetos no usados (1arbage Collector, GC). Este recolector de objetos
no usados se encarga de comprobar constantemente cuando un objeto no se est
usando y es el que decide cuando hay que llamar al destructor.
Debido a esta caracterstica de .NET, si nuestra clase hace uso de recursos externos
que necesiten ser eliminados cuando la el objeto ya no se vaya a seguir usando,
debemos definir un mtodo que sea el encargado de realizar esa liberacin, pero
ese mtodo debemos llamarlo de forma manual, ya que, aunque en .NET existen
formas de hacer que esa llamada sea automtica, nunca tenderemos la seguridad
de que se llame en el momento oportuno, y esto es algo que, segn que casos,
puede ser un inconveniente.

Becomendacin3
Si nuestra clase utiliza recursos externos, por ejemplo un fichero o una
base de datos, debemos definir un mtodo que se encargue de
liberarlos y a ese mtodo debemos encargarnos de llamarlo cuando ya
no lo necesitemos.
Por definicin a este tipo de mtodos se les suele dar el nombre Close
o Dispose, aunque este ltimo tiene un significado especial y por
convencin solo debemos usarlo siguiendo las indicaciones de la
documentacin.

Estructuras3 Tipos por valor definidos por el usuario
De la misma forma que podemos definir nuestros propios tipos de datos por
referencia, Visual Basic 2005 nos permite crear nuestros propios tipos por valor.
Para crear nuestros tipos de datos por referencia, usamos la "instruccin" Class, por
tanto es de esperar que tambin exista una instruccin para crear nuestros tipos
por valor, y esa instruccin es: Structure, por eso en Visual Basic 2005 a los tipos
por valor definidos por el usuario se llaman estructuras.
46

Nota3
El equivalente en VB6 a una estructura de Visual Basic 2005 es Type,
aunque es solo eso: un parecido, pero realmente no es equivalente, al
menos al 100%, tal como tendremos oportunidad de comprobar en
esta leccin.

Las estructuras pueden contener los mismos miembros que las clases, aunque
algunos de ellos se comporten de forma diferente o al menos tengan algunas
restricciones, como que los campos definidos en las estructuras no se pueden
inicializar al mismo tiempo que se declaran o no pueden contener constructores
"simples", ya que el propio compilador siempre se encarga de crearlo, para as
poder inicializar todos los campos definidos.
Otra de las caractersticas de las estructuras es que no es necesario crear una
instancia para poder usarlas, ya que es un tipo por valor y los tipos por valor no
necesitan ser instanciados para que existan.
"efinir una estructura
Las estructuras se definen usando la palabra Structure seguida del nombre y acaba
usando las instrucciones %nd Structure.
El siguiente cdigo define una estructura llamada Punto en la que tenemos dos
campos pblicos.
Str!ct!re ?!nto
?!blic L As Integer
?!blic M As Integer
n% Str!ct!re
Para usarla podemos hacer algo como esto:
Dim 2 As ?!nto
2/L = 100
2/M = N5
Tambin podemos usar New al declarar el objeto:
Dim 2 As AeJ ?!nto
47
Aunque en las estructuras, usar New, sera algo redundante y por tanto no
necesario.

Las estructuras siempre se almacenan en la pila, por tanto deberamos tener la
precaucin de no crear estructuras con muchos campos o con muchos miembros, ya
que esto implicara un mayor consumo del "preciado" espacio de la pila.

Constructores de las estructuras
Tal y como hemos comentado, las estructuras siempre definen un constructor sin
parmetros, este constructor no lo podemos definir nosotros, es decir, siempre
existe y es el que el propio compilador de Visual Basic 2005 define.
Por tanto, si queremos agregar algn constructor a una estructura, este debe tener
parmetros y, tal como ocurre con cualquier mtodo o como ocurre en las clases,
podemos tener varias sobrecargas de constructores parametrizados en las
estructuras. La forma de definir esos constructores es como vimos en las clases:
usando distintas sobrecargas de un mtodo llamado $e!, en el caso de las
estructuras tambin podemos usar la palabra clave (e para referirnos a la instancia
actual.
Esto es particularmente prctico cuando los parmetros del constructor se llaman
de la misma forma que los campos declarados en la estructura, tal como ocurre en
el constructor mostrado en la siguiente definicin de la estructura Punto.
Str!ct!re ?!nto
?!blic L As Integer
?!blic M As Integer
4
S!b AeJ(,-$al G As Integer, ,-$al - As Integer)
He/L = G
He/M = -
n% S!b
n% Str!ct!re


48
Nota3
Tanto en las estructuras como en las clases podemos tener
constructores compartidos, en el caso de las estructuras, este tipo de
constructor es el nico que podemos declarar sin parmetros.


"estructores de las estructuras
Debido a que las estructuras son tipos por valor y por tanto una variable declarada
con un tipo por valor "contiene el valor en si misma", no podemos destruir este tipo
de datos, lo ms que conseguiramos al asignarle un valor nulo ($ot"ing) sera
eliminar el contenido de la variable, pero nunca podemos destruir ese valor. Por
tanto, en las estructuras no podemos definir destructores.


'os miembros de una estructura
Como hemos comentado, los miembros o elementos que podemos definir en una
estructura son los mismos que ya vimos en las clases. Por tanto aqu veremos las
diferencias que existen al usarlos en las estructuras.
Campos
Como vimos, las variables declaradas a nivel del tipo, son los campos, la principal
diferencia con respecto a las clases, es que los campos de una estructura no pueden
inicialiarse en la declaracin y el valor que tendrn inicialmente es un valor "nulo",
que en el caso de los campos de tipo numricos es un cero.
Por tanto, si necesitamos que los campos tengan algn valor inicial antes de
usarlos, deberamos indicarlo a los usuarios de nuestra estructura y proveer un
constructor que realice las inicializaciones correspondientes, pero debemos recordar
que ese constructor debe tener algn parmetro, ya que el predeterminado sin
parmetros no podemos "reescribirlo".
Los nicos campos que podemos inicializar al declararlos son los campos
compartidos, pero como tendremos oportunidad de ver, estos campos sern
accesibles por cualquier variable declarada y cualquier cambio que realicemos en
ellos se ver reflejado en el resto de "instancias" de nuestro tipo.
Mtodos y otros elementos
El resto de los miembros de una estructura se declaran y usan de la misma forma
que en las clases, si bien debemos tener en cuenta que el modificador de
49
accesibilidad predeterminado para los miembros de una estructura es +ublic,
(incluso si son campos declarados con D2m).
Otro detalle a tener en cuenta es que en una estructura siempre debe existir al
menos un evento o un campo no compartido, no se permiten estructuras en las que
solo tienen constantes, mtodos y/o propiedades, estn o no compartidos.


C(mo usar las estructuras
Tal como hemos comentado las estructuras son tipos por valor, para usar los tipos
por valor no es necesario instanciarlos explcitamente, ya que el mero hecho de
declararlos indica que estamos creando un nuevo objeto en memoria. Por tanto, a
diferencia de las clases o tipos por referencia, cada variable definida como un tipo
de estructura ser independiente de otras variables declaradas, aunque no las
hayamos instanciado.
Esta caracterstica de las estructuras nos permite hacer copias "reales" no copia de
la referencia (o puntero) al objeto en memoria como ocurre con los tipos por
referencia.
Vemoslos con un ejemplo.
Dim 2 As AeJ ?!nto(100, N5)
Dim 21 As ?!nto
21 = 2
21/L = 200
4 2/L 5ale 100 - 21/L 5ale 200
En este trozo de cdigo definimos e instanciamos una variable del tipo 8unto, a
continuacin declaramos otra variable del mismo tipo y le asignamos la primera, si
estos tipos fuesen por referencia, tanto una como la otra estaran haciendo
referencia al mismo objeto en memoria, y cualquier cambio realizado a cualquiera
de las dos variables afectaran al mismo objeto, pero en el caso de las estructuras
(y de los tipos por valor), cada cambio que realicemos se har sobre un objeto
diferente, por tanto la asignacin del valor 200 al campo L de la variable p$ solo
afecta a esa variable, dejando intacto el valor original de la variable p.

4ccesi#ilidad % .m#ito
Tal y como comentamos anteriormente, dependiendo de dnde y cmo estn
declarados los tipos de datos y los miembros definidos en ellos, tendremos o no
acceso a esos elementos.
50
Recordemos que el mbito es el alcance con el que podemos acceder a un elemento
y depende de dnde est declarado, por otro lado, la accesibilidad depende de cmo
declaremos cada uno de esos elementos.

4mbito
Dependiendo de donde declaremos un miembro o un tipo, ste tendr mayor
alcance o cobertura, o lo que es lo mismo, dependiendo del mbito en el que
usemos un elemento, podremos acceder a l desde otros puntos de nuestro cdigo.
A continuacin veremos con detalle los mbitos en los que podemos declarar los
distintos elementos de Visual Basic 2005.
Im#ito de #lo&ue3 Disponible nicamente en el bloque de cdigo en el que
se ha declarado.
Por ejemplo, si declaramos una variable dentro de un bucle )or o un If T"en,
esa variable solo estar accesible dentro de ese bloque de cdigo.
Im#ito de procedimiento3 Disponible nicamente dentro del procedimiento
en el que se ha declarado. Cualquier variable declarada dentro de un
procedimiento (mtodo o propiedad) solo estar accesible en ese
procedimiento y en cualquiera de los bloques internos a ese procedimiento.
Im#ito de mdulo3 Disponible en todo el cdigo del mdulo, la clase o la
estructura donde se ha declarado. Las variables con mbito a nivel de
mdulo, tambin estarn disponibles en los procedimientos declarados en el
mdulo (clase o estructura) y por extensin a cualquier bloque dentro de cada
procedimiento.
Im#ito de espacio de nom#res3 Disponible en todo el cdigo del espacio
de nombres. Este es el nivel mayor de cobertura o alcance, aunque en este
nivel solo podemos declarar tipos como clases, estructuras y enumeraciones,
ya que los procedimientos solamente se pueden declarar dentro de un tipo.

Nota3
Por regla general, cuando declaramos una variable en un mbito, dicha
variable "ocultar" a otra que tenga el mismo nombre y est definida
en un bloque con mayor alcance, aunque veremos que en Visual Basic
2005 existen ciertas restricciones dependiendo de dnde declaremos
esas variables.

En VB6 los mbitos disponibles solamente eran los de mdulo y procedimiento, en
estos casos, cualquier variable declarada en un procedimiento oculta a una definida
en un mdulo.
En Visual Basic 2005 podemos definir una variable dentro de un bloque de cdigo,
en ese caso dicha variable solo ser accesible dentro de ese bloque. Aunque, como
veremos a continuacin, en un procedimiento solamente podremos definir variables
que no se oculten entre s, estn o no dentro de un bloque de cdigo.
51

mbito de bloque
En los siguientes ejemplos veremos cmo podemos definir variables para usar
solamente en el bloque en el que estn definidas.
Los bloques de cdigo en los que podemos declarar variables son los bucles, ()or3
Do3 4"ile), y los bloques condicionales, (If3 Select).
Por ejemplo, dentro de un procedimiento podemos tener varios de estos bloques y
por tanto podemos definir variables "internas" a esos bloques:
Dim n As Integer = 3
4
)or i As Integer = 1 1o 10
Dim # As Integer
# B= 1
I8 # ( n 1hen
4///
n% I8
AeGt
4
I8 n ( 5 1hen
Dim # As Integer = n O 3
n% I8
4
Do
Dim # As Integer
)or i As Integer = 1 1o n
# B= i
AeGt
I8 # * 10 1hen Git Do
'oo2
52
La variable n estar disponible en todo el procedimiento, por tanto podemos
acceder a ella desde cualquiera de los bloques.
En el primer bucle )or, definimos la variable i como la variable a usar de contador,
esta variable solamente estar accesible dentro de este bucle )or. Lo mismo ocurre
con la variable (.
En el primer If definimos otra variable (, pero esa solo ser accesible dentro de este
bloque If y por tanto no tiene ninguna relacin con la definida en el bucle )or
anterior.
En el bucle Do volvemos a definir nuevamente una variable (, a esa variable la
podemos acceder solo desde el propio bucle Do y cualquier otro bloque de cdigo
interno, como es el caso del bucle )or, en el que nuevamente declaramos una
variable llamada i, que nada tiene que ver con el resto de variables declaradas con
el mismo nombre en los otros bloques.
Lo nico que no podemos hacer en cualquiera de esos bloques, es declarar una
variable llamada n, ya que al estar declarada en el procedimiento, el compilador de
Visual Basic 2005 nos indicar que no podemos ocultar una variable previamente
definida fuera del bloque, tal como podemos ver en la figura 1.12.
Fi'ura $.$2. Error al ocultar una varia#le definida en un procedimiento
Esta restriccin solo es aplicable a las variables declaradas en el procedimiento, ya
que si declaramos una variable a nivel de mdulo, no habr ningn problema para
usarla dentro de un bloque, esto es as porque en un procedimiento podemos
declarar variables que se llamen de la misma forma que las declaradas a nivel de
mdulo, aunque stas ocultarn a las del "nivel" superior.

mbito de procedimiento
Las variables declaradas en un procedimiento tendrn un mbito o cobertura que
ser el procedimiento en el que est declaradas, y como hemos visto, ese mbito
incluye tambin cualquier bloque de cdigo declarado dentro del procedimiento.
Estas variables ocultarn a las que se hayan declarado fuera del procedimiento, si
bien, dependiendo del tipo de mdulo, podremos acceder a esas variables
"externas" indicando el nombre completo del mdulo o bien usando la instruccin
(e, tal como vimos en el cdigo del constructor parametrizado de la estructura
8unto.
Pero mejor vemoslo con un ejemplo. En el siguiente cdigo, definimos una clase en
la que tenemos un campo llamado Nom#re, tambin definimos un mtodo en el
53
que internamente se utiliza una variable llamada nombre, para acceder a la variable
declarada en la clase, tendremos que usar la instruccin o palabra clave (e.
?!blic Class Cliente
?!blic Aombre As String = "@!an"
)!nction Hostrar() As String
Dim nombre As String = "?e2ita"
"et!rn "Gterno= " P He/Aombre P ", interno= " P nombre
n% )!nction
n% Class
En este ejemplo, el hecho de que una variable est declarada con la letra ene en
mayscula o en minscula no implica ninguna diferencia, ya que Visual Basic 2005
al igual que VB6 no hace distinciones de este tipo, si bien, en Visual Basic 2005 no
se cambia automticamente el "case" de las variables, salvo cuando estn en el
mismo nivel de mbito; en cambio, si en VB6 declaramos una variable con el mismo
nombre, aunque est en un mbito diferente, siempre se usar el estado de
maysculas/minsculas de la ltima definicin.

mbito de mdulo
Cuando hablamos de mdulos, nos estamos refiriendo a una clase, a una estructura
o a cualquier otro tipo de datos que nos permita .NET.
En estos casos, las variables declaradas dentro de un tipo de datos sern visibles
desde cualquier parte de ese tipo, siempre teniendo en cuenta las restricciones
mencionadas en los casos anteriores.

mbito de espacio de nombres
Los espacios de nombres son los contenedores de tipos de datos de mayor nivel, y
sirven para contener definiciones de clases, estructuras, enumeraciones y
delegados. Cualquier tipo definido a nivel de espacio de nombres estar disponible
para cualquier otro elemento definido en el mismo espacio de nombres.
Al igual que ocurre en el resto de mbitos "inferiores", si definimos un tipo en un
espacio de nombres, podemos usar ese mismo nombre para nombrar a un
procedimiento o a una variable, en cada caso se aplicar el mbito correspondiente
y, tal como vimos anteriormente, tendremos que usar nombres nicos para poder
acceder a los nombres definidos en niveles diferentes.

54

'a palabra clave 5lobal
En Visual Basic 2005 podemos definir espacios de nombres cuyos nombres sean los
mismos que los definidos en el propio .NET Framework, para evitar conflictos de
mbitos, podemos usar la palabra clave 1lobal para acceder a los que se han
definido de forma "global" en .NET.
Por ejemplo, si tenemos el siguiente cdigo en el que definimos una clase dentro de
un espacio de nombres llamado System y queremos acceder a uno de los tipos
definidos en el espacio de nombres System de .NET, tendremos un problema:
Aames2ace S-stem
Class Cliente
?!blic Aombre As String
?!blic %a% As S-stem/Int32
n% Class
n% Aames2ace
El problema es que el compilador de Visual Basic 2005 nos indicar que el tipo
Int32 no est definido, ya que intentar buscarlo dentro del mbito que actualmente
tiene, es decir, la declaracin que nosotros hemos hecho de System, por tanto para
poder acceder al tipo Int32 definido en el espacio de nombres "global" System de
.NET tendremos que usar la instruccin 1lobal, por suerte el IDE de Visual Basic
2005 Express reconoce este tipo de error y nos ofrece ayuda para poder solventar el
conflicto, tal como vemos en la figura 1.13:
Fi'ura $.$<. 4%uda del I/E en los conflictos de espacios nom#res 'lo#ales

Nota3
Afortunadamente este conflicto con los espacios de nombres no ser
muy habitual para los desarrolladores que usemos el idioma de
55
Cervantes, por la sencilla razn de que los espacios de nombres de
.NET Framework suelen estar definidos usando palabras en ingls.


Accesibilidad
La accesibilidad es la caracterstica que podemos aplicar a cualquiera de los
elementos que definamos en nuestro cdigo. Dependiendo de la accesibilidad
declarada tendremos distintos tipos de accesos a esos elementos.
Los modificadores de accesibilidad que podemos aplicar a los tipos y elementos
definidos en nuestro cdigo pueden ser cualquiera de los mostrados en la siguiente
lista:
8u#lic3 Acceso no restringido. Este es modificador de accesibilidad con mayor
"cobertura", podemos acceder a cualquier miembro pblico desde cualquier
parte de nuestro cdigo. Aunque, como veremos, este acceso no restringido
puede verse reducido dependiendo de dnde lo usemos.
8rotected3 Acceso limitado a la clase contenedora o a los tipos derivados de
esta clase. Este modificador solamente se usa con clases que se deriven de
otras.
Friend3 Acceso limitado al proyecto actual. Visual Basic 2005 aplica este
modificador de forma predeterminada a los procedimientos declarados en las
clases.
8rotected Friend3 Acceso limitado al proyecto actual o a los tipos derivados
de la clase contenedora. Una mezcla de los dos modificadores anteriores.
8rivate3 Acceso limitado al tipo contenedor. Es el ms restrictivos de todos
los modificadores de accesibilidad y en el caso de los campos declarados en
las clases (Class) equivale a usar Dim.
Estos modificadores de accesibilidad los podemos usar tanto en clases, estructuras,
interfaces, enumeraciones, delegados, eventos, mtodos, propiedades y campos.
Aunque no sern aplicables en espacios de nombres ($amespace) ni clases de tipo
Module, en estos dos casos siempre tendrn cobertura pblica, si bien no se permite
el uso de ningn modificador.

Accesibilidad de las variables en los procedimientos
Las variables declaradas dentro de un procedimiento solo son accesibles dentro de
ese procedimiento, en este caso solo se puede aplicar el mbito privado, aunque no
podremos usar la instruccin +riate, sino Dim o Static.

56
Nota3
La palabra clave Static, tiene el mismo significado que en VB6, y nos
permite definir una variable privada (o local) al procedimiento para
que mantenga el valor entre diferentes llamadas a ese procedimiento;
esto contrasta con el resto de variables declaradas en un
procedimiento cuya duracin es la misma que la vida del propio
procedimiento, por tanto, las variables no estticas pierden el valor al
terminar la ejecucin del procedimiento.


'as accesibilidades predeterminadas
La accesibilidad de una variable o procedimiento en la que no hemos indicado el
modificador de accesibilidad depender del sitio en el que la hemos declarado.
Por ejemplo, en las estructuras si definimos los campos usando Dim, estos tendrn
un mbito igual que si le hubisemos aplicado el modificador +ublic; sin embargo,
esa misma variable declarada en una clase (Class o (odule) tendr una
accesibilidad +riate. As mismo, si el elemento que declaramos es un procedimiento
y no indicamos el modificador de mbito, ste tendr un mbito de tipo +ublic si lo
definimos en una estructura y si el lugar en el que lo declaramos es una clase (o
(odule), ste ser )riend.
En la siguiente tabla tenemos la accesibilidad predeterminada de cada tipo (clase,
estructura, etc.), as como de las variables declaradas con Dim y de los
procedimientos en los que no se indican el modificador de accesibilidad.
Tipo del tipo de las varia#les
declaradas con
/im
de los
procedimientos
Class Friend Private Friend
Module Friend Private Friend
Structure Friend Public Public
Enum Public
Friend
N.A.
(los miembros
siempre son
pblicos)
N.A.
Interface Friend N.A.
(no se pueden
declarar variables)
Public
(no se permite
indicarlo)
Ta#la $.<. *a accesi#ilidad predeterminada de los tipos
Tal como podemos ver en la tabla 1.3, la accesibilidad predeterminada, (la que
tienen cuando no se indica expresamente con un modificador), de todos los tipos es
57
)riend, es decir, accesible a todo el proyecto, aunque en el caso de las
enumeraciones el modificador depende de dnde se declare dicha enumeracin, si
est declarada a nivel de espacio de nombres ser )riend, en el resto de los casos
ser +ublic.
En la tercera columna tenemos la accesibilidad predeterminada cuando declaramos
las variables con Dim, aunque en las interfaces y en las enumeraciones no se
permiten declarar variables.
La ltima columna es la correspondiente a los procedimientos, en el caso de las
interfaces no se puede aplicar ningn modificador de accesibilidad y de forma
predeterminada son pblicos.

En esta otra tabla tenemos la accesibilidad permitida en cada tipo as como las que
podemos indicar en los miembros de esos tipos.
Tipo del tipo de los miem#ros
Class Public
Friend
Private
Protected
Protected Friend
Public
Friend
Private
Protected
Protected Friend
Module Public
Friend
Public
Friend
Private
Structure Public
Friend
Private
Public
Friend
Private
Enum Public
Friend
Private
N.A.
Interface Public
Friend
Private
Protected
Protected Friend
N.A.
Siempre son pblicos
Ta#la $.=. 4ccesi#ilidades permitidas en los tipos
Algunos de los modificadores que podemos indicar en los tipos dependen de dnde
declaremos esos tipos, por ejemplo, tan solo podremos indicar el modificador
privado de las enumeraciones cuando estas se declaren dentro de un tipo. En el
caso de las clases e interfaces, los modificadores +rotected y +rotected )riend solo
podremos aplicarlos cuando estn declaradas dentro de una clase (Class).

58
Anidaci(n de tipos
Tal como hemos comentado en el prrafo anterior, podemos declarar tipos dentro de
otros tipos, por tanto el mbito y accesibilidad de esos tipos dependen del mbito y
accesibilidad del tipo que los contiene. Por ejemplo, si declaramos una clase con
acceso )riend, cualquier tipo que esta clase contenga siempre estar supeditado al
mbito de esa clase, por tanto si declaramos otro tipo interno, aunque lo
declaremos como +ublic, nunca estar ms accesible que la clase contenedora,
aunque en estos casos no habr ningn tipo de confusin, ya que para acceder a los
tipos declarados dentro de otros tipos siempre tendremos que indicar la clase que
los contiene.
En el siguiente cdigo podemos ver cmo declarar dos clases "anidadas". Tal como
podemos comprobar, para acceder a la clase Salario debemos indicar la clase
Cliente, ya que la nica forma de acceder a una clase anidada es mediante la clase
contenedora.
)rien% Class Cliente
?!blic Aombre As String
?!blic Class Salario
?!blic Im2orte As Decimal
n% Class
n% Class
4 ?ara !sar la clase Salario %ebemos %eclararla %e esta 8ormaD
Dim s As AeJ Cliente/Salario
s/Im2orte = 2200

Los tipos anidables
Cualquiera de los tipos mostrados en la tabla 1.4, excepto las enumeraciones,
pueden contener a su vez otros tipos. La excepcin es el tipo (odule que aunque
puede contener a otros tipos, no puede usarse como tipo anidado. Una enumeracin
siempre puede usarse como tipo anidado.

Nota3
Los espacios de nombres tambin pueden anidarse y contener a su vez
cualquiera de los tipos mostrados en la tabla 1.4, incluso tipos Module.
59


l nombre completo de un tipo
Tal como hemos visto, al poder declarar tipos dentro de otros tipos y estos a su vez
pueden estar definidos en espacios de nombres, podemos decir que el nombre
"completo" de un tipo cualquiera estar formado por el/los espacios de nombres y
el/los tipos que los contiene, por ejemplo si la clase -liente definida anteriormente
est a su vez dentro del espacio de nombres 4m#itos, el nombre completo ser:
4m#itos.-liente y el nombre completo de la clase Salario ser:
4m#itos.-liente.Salario.
Aunque para acceder a la clase -liente no es necesario indicar el espacio de
nombres, al menos si la queremos usar desde cualquier otro tipo declarado dentro
de ese espacio de nombres, pero si nuestra intencin es usarla desde otro espacio
de nombre externo a 4m#itos, en ese caso si que tendremos que usar el nombre
completo.
Por ejemplo, en el siguiente cdigo tenemos dos espacios de nombres que no estn
anidados, cada uno de ellos declara una clase y desde una de ellas queremos
acceder a la otra clase, para poder hacerlo debemos indicar el nombre completo, ya
que en caso contrario, el compilador de Visual Basic 2005 sera incapaz de saber a
que clase queremos acceder.
Aames2ace Fno
?!blic Class Clase1
?!blic Aombre As String
n% Class
n% Aames2ace
Aames2ace Dos
?!blic Class Clase2
?!blic Aombre As String
S!b Hain()
Dim c1 As AeJ Fno/Clase1
c1/Aombre = "?e2e"
n% S!b
n% Class
n% Aames2ace
60
Esto mismo lo podemos aplicar en el caso de que tengamos dos clases con el mismo
nombre en espacios de nombres distintos.

Nota3
En el mismo proyecto podemos tener ms de una declaracin de un
espacio de nombres con el mismo nombre, en estos casos el
compilador lo tomar como si todas las clases definidas estuvieran
dentro del mismo espacio de nombres, aunque estos estn definidos
en ficheros diferentes.


Importacin de espacios de nombres
Tal como hemos comentado, los espacios de nombres pueden contener otros
espacios de nombres y estos a su vez tambin pueden contener otros espacios de
nombres o clases, y como hemos visto, para poder acceder a una clase que no est
dentro del mismo espacio de nombres debemos indicar el "nombre completo".
Para evitar estar escribiendo todos los espacios de nombres en los que est la clase
que nos interesa declarar, podemos usar una especie de acceso directo o para que
lo entendamos mejor, podemos crear una especie de "Path", de forma que al
declarar una variable, si esta no est definida en el espacio de nombres actual, el
compilador busque en todos los espacios de nombres incluidos en esas rutas
(paths).
Esto lo conseguimos usando la instruccin Imports seguida del espacio de nombres
que queremos importar o incluir en el path de los espacios de nombres.
Podemos usar tantas importaciones de espacios de nombres como necesitemos y
estas siempre deben aparecer al principio del fichero, justo despus de las
instrucciones Options.
Por ejemplo, si tenemos el cdigo anterior y hacemos la importacin del espacio de
nombres en el que est definida la clase Clase1:
Im2orts Fno
podremos acceder a esa clase de cualquiera de estas dos formas:
Dim c1 As AeJ Fno/Clase1
Dim c1 As AeJ Clase1

61
Alias de espacios de nombres
Si hacemos demasiadas importaciones de nombres, el problema con el que nos
podemos encontrar es que el IntelliSense de Visual Basic 2005 no sea de gran
ayuda, ya que mostrar una gran cantidad de clases, y seguramente nos resultar
ms difcil encontrar la clase a la que queremos acceder, o tambin podemos
encontrarnos en ocasiones en las que nos interese usar un nombre corto para
acceder a las clases contenidas en un espacio de nombres, por ejemplo, si
queremos indicar de forma explcita las clases de un espacio de nombres como el de
(icrosoft.#isualBasic, podemos hacerlo de esta forma:
Im2orts 5b = Hicroso8t/$is!al,asic
De esta forma podemos usar el "alias" v# para acceder a las clases y dems tipos
definidos en ese espacio de nombres.
En las figuras 1.14 1.15 podemos ver las dos formas de acceder a las clases del
espacio de ese espacio de nombres, en el primer caso sin usar un alias y en el
segundo usando el alias v#.
Fi'ura $.$=. *os miem#ros de un espacio de nom#res usando el nom#re
completo

62
Fi'ura $.$5. 4cceder a los miem#ros de un espacio de nom#res usando un
alias

8ropiedades
Las propiedades son los miembros de los tipos que nos permiten acceder a los datos
que dicho tipo manipula. Normalmente una propiedad est relacionada con un
campo, de forma que el campo sea el que realmente contenga el valor y la
propiedad simplemente sea una especie de mtodo a travs del cual podemos
acceder a ese valor.
Debido a que el uso de las propiedades realmente nos permite acceder a los valores
de una clase (o tipo), se suelen confundir los campos con las propiedades, de hecho
en VB6 si definimos una variable pblica, sta se convierte en una propiedad de la
clase, en Visual Basic 2005 casi ocurre lo mismo, pero realmente un campo (o
variable) pblico no es una propiedad, al menos en el sentido de que el propio .NET
Framework no lo interpreta como tal, aunque en la prctica nos puede parecer que
es as, ya que se utilizan de la misma forma. Pero no debemos dejarnos llevar por la
comodidad y si no queremos perder funcionalidad, debemos diferenciar en nuestro
cdigo las propiedades de los campos.
Lo primero que debemos tener presente es que gracias a esta diferenciacin que
hace .NET Framework, (realmente VB6 tambin la hace), podemos poner en
prctica una de las caractersticas de la programacin orientada a objetos: la
encapsulacin, de forma, que la manipulacin de los datos que una clase contiene
siempre se deben hacer de forma "interna" o privada a la clase, dejando a las
propiedades la posibilidad de que externamente se manipulen, de forma controlada,
esos datos. De esta forma tendremos mayor control sobre cmo se acceden o se
asignan los valores a esos datos, ya que al definir una propiedad, tal como hemos
comentado, realmente estamos definiendo un procedimiento con el cual podemos
63
controlar cmo se acceden a esos datos.
Este concepto no ha cambiado, al menos en el fondo, con respecto a como lo
hacemos actualmente con VB6, ya que en VB6 tambin podemos declarar
procedimientos del tipo propiedad, aunque la forma de hacerlo en Visual Basic 2005
si que ha cambiado un poco, tal como tendremos ocasin de ver a continuacin.

"efinir una propiedad
Debido a que una propiedad realmente nos permite acceder a un dato que la clase
(o estructura) manipula, siempre tendremos un campo relacionado con una
propiedad. El campo ser el que contenga el valor y la propiedad ser la que nos
permita manipular ese valor.
En Visual Basic 2005, las propiedades las declaramos usando la instruccin +roperty
y la definicin de la misma termina con %nd +roperty, esto es prcticamente igual (o
casi) que en VB6, la diferencia principal es que en VB6 cuando definimos una
propiedad, debemos hacerlo en partes, por ejemplo, si queremos definir cuando
accedemos al valor, declaramos esa accin usando las instrucciones +roperty 1et y
para definir la parte de la propiedad que asigna un nuevo valor, lo hacemos
mediante +roperty Let. En Visual Basic 2005 esas dos acciones, la de lectura (1%T)
y asignacin (L%T), las debemos indicar en dos bloques dentro de la propia
declaracin de la propiedad, el bloque que nos permite acceder al valor de la
propiedad estar indicado por la instruccin 1et y acaba con %nd 1et, por otra
parte, el bloque usado para asignar un valor a la propiedad se define mediante la
instruccin Set y acaba con %nd Set.

Nota3
En VB6 realmente disponemos de tres bloques o partes en la definicin
de una propiedad:
Property Get, que nos permite acceder al valor de la propiedad.
Propery Let, que nos permite asignar un valor a la propiedad.
Property Set, el cual lo usamos cuando la propiedad representa un
objeto y queremos asignar dicho objeto a la propiedad.
La diferencia entre Let y Set es que el primero se usar en valores de
tipos por valor y el segundo en tipos por referencia, aunque el
compilador de VB6 realmente usar uno u otro segn asignemos el
valor directamente a la propiedad o usemos la instruccin Set para
hacer esa asignacin.

Tal como indicamos en la nota anterior, en VB6 existen dos formas de asignar
valores a una propiedad de una clase, pero en Visual Basic 2005 no existe ese
"conflicto" en la forma de asignar los valores, ya que siempre que se asigna un valor
a una propiedad se hace sin usar la instruccin Set, de hecho no se puede usar Set
para realizar asignaciones a propiedades en VB2005.
64
Veamos como definir una propiedad en Visual Basic 2005:
?!blic Class Cliente
?ri5ate +nombre As String
?!blic ?ro2ert- Aombre() As String
;et
"et!rn +nombre
n% ;et
Set(,-$al 5al!e As String)
+nombre = 5al!e
n% Set
n% ?ro2ert-
n% Class
Como podemos comprobar tenemos dos bloques de cdigo, el bloque 1et que es el
que se usa cuando queremos acceder al valor de la propiedad, por tanto
devolvemos el valor del campo privado usado para almacenar ese dato. El bloque
Set es el usado cuando asignamos un valor a la propiedad, este bloque tiene
definido un parmetro (alue) que representa al valor que queremos asignar a la
propiedad.
Aunque en Visual Basic 2005 las definiciones para obtener o asignar el valor de la
propiedad se hacen en bloques definidos dentro de un procedimiento del tipo
+roperty, esta forma de definir las propiedades no se diferencia demasiado a como
lo hacemos en VB6, y una vez que nos acostumbremos lo veremos como una forma
ms "compacta" de hacerlo.


,ropiedades de solo lectura
En ciertas ocasiones nos puede resultar interesante que una propiedad sea de solo
lectura, de forma que el valor que representa no pueda ser cambiado.
En VB6 para definir una propiedad de solo lectura bastaba con definir solo la parte
1et de la propiedad, en Visual Basic 2005 tambin se hace de esa forma, pero,
aunque realmente es algo ..., debemos indicar expresamente que esa es nuestra
intencin, por tanto no solo basta con definir solo el bloque 1et, sino que debemos
usar el modificador 'eadOnly para que el compilador de Visual Basic 2005 acepte la
declaracin:
65
?!blic "ea%0nl- ?ro2ert- Ho-() As Date
;et
"et!rn Date/AoJ
n% ;et
n% ?ro2ert-

,ropiedades de solo escritura
De igual forma, si queremos definir una propiedad que sea de solo escritura, solo
definiremos el bloque Set, pero al igual que ocurre con las propiedades de solo
lectura, debemos indicar expresamente que esa es nuestra intencin, para ello
usaremos la palabra clave 4riteOnly:
?!blic <rite0nl- ?ro2ert- ?assJor%() As String
Set(,-$al 5al!e As String)
I8 5al!e = "blablabla" 1hen
4 oQ
n% I8
n% Set
n% ?ro2ert-


"iferente accesibilidad para los blo6ues 5et y Set
En las propiedades normales (de lectura y escritura), podemos definir diferentes
niveles de accesibilidad a cada uno de los dos bloques que forman una propiedad.
Por ejemplo, podramos definir el bloque 1et como pblico, (siempre accesible), y el
bloque Set como +riate, de forma que solo se puedan realizar asignaciones desde
dentro de la propia clase.
Por ejemplo, el salario de un empleado podramos declararlo para que desde
cualquier punto se pueda saber el importe, pero la asignacin de dicho importe solo
estar accesible para los procedimientos definidos en la propia clase:
?!blic Class m2lea%o
66
?ri5ate +salario As Decimal
?!blic ?ro2ert- Salario() As Decimal
;et
"et!rn +salario
n% ;et
?ri5ate Set(,-$al 5al!e As Decimal)
+salario = 5al!e
n% Set
n% ?ro2ert-
n% Class
Para hacer que el bloque Set sea privado, lo indicamos con el modificador de
accesibilidad +riate, al no indicar ningn modificador en el bloque 1et, ste ser el
mismo que el de la propiedad.
En VB6 podemos hacer esto mismo definiendo como pblico la declaracin de
+roperty 1et y como privado la de la asignacin: +roperty Let.

Nota3
El nivel de accesibilidad de los bloques Get o Set debe ser igual o
inferior que el de la propiedad, por tanto si la propiedad la declaramos
como Private, no podemos definir como pblico los bloques Get o Set.


,ropiedades predeterminadas
Una cosa que echamos en falta en Visual Basic 2005 son las propiedades
predeterminadas, aunque existen no son exactamente igual que en VB6. En VB6
podemos definir como propiedad predeterminada cualquiera de las propiedades de
la clase, aunque la forma de hacerlo es un poco "rebuscada" y poco intuitiva, al
menos podemos definir como predeterminada la que ms nos interese. En Visual
Basic 2005 no podemos definir como predeterminada cualquier propiedad, ya que
debido a como se realizan las asignaciones de objetos en .NET (sin necesidad de
usar Set), siempre debemos indicar la propiedad a la que queremos asignar el valor,
porque en caso de que no se indique ninguna, el compilador interpretar que lo que
queremos asignar es un objeto y no un valor a una propiedad.
Para evitar conflictos o tener que usar alguna instruccin "extra" para que se sepa si
lo que queremos asignar es un valor o un objeto, en Visual Basic 2005 las
67
propiedades predeterminadas siempre deben ser parametrizadas, es decir, tener
como mnimo un parmetro.
Para indicar que una propiedad es la propiedad por defecto lo debemos hacer
usando la instruccin Default:
De8a!lt ?!blic "ea%0nl- ?ro2ert- Item(,-$al in%eG As Integer) As
m2lea%o
;et
4 ///
n% ;et
n% ?ro2ert-
Como vemos en este ejemplo, una propiedad por defecto puede ser de solo lectura
y tambin de solo escritura o de lectura/escritura.
Para usar esta propiedad, al ser la propiedad por defecto, no es necesario indicar el
nombre de la propiedad, aunque si as lo deseamos podemos indicarla, aunque en
este caso no tendra mucha utilidad el haberla definido como propiedad por defecto:
Dim e As AeJ m2lea%o
Dim e1 As m2lea%o = e(2)
4 1ambiRn 2o%emos !sarla in%ican%o el nombre %e la 2ro2ie%a%D
Dim e2 As m2lea%o = e/Item(2)

!obrecar"a de propiedades predeterminadas
Debido a que las propiedades predeterminadas de Visual Basic 2005 deben recibir
un parmetro, podemos crear sobrecargas de una propiedad predeterminada,
aunque debemos recordar que para que esa sobrecarga pueda ser posible, el tipo o
nmero de argumentos deben ser distintos entre las distintas sobrecargas, por
ejemplo podramos tener una sobrecarga que reciba un parmetro de tipo entero y
otra que lo reciba de tipo cadena:
De8a!lt ?!blic "ea%0nl- ?ro2ert- Item(,-$al in%eG As Integer) As
m2lea%o
;et
4 ///
n% ;et
n% ?ro2ert-
68
De8a!lt ?!blic ?ro2ert- Item(,-$al in%eG As String) As m2lea%o
;et
4 ///
n% ;et
Set(,-$al 5al!e As m2lea%o)
4
n% Set
n% ?ro2ert-
Incluso como vemos en este cdigo una de las sobrecargas puede ser de solo
lectura y la otra de lectura/escritura. Lo que realmente importa es que el nmero o
tipo de parmetros de cada sobrecarga sea diferente.

Las propiedades predeterminadas tienen sentido en Visual Basic 2005 cuando
queremos que su uso sea parecido al de un array. Por tanto es habitual que las
clases de tipo coleccin sean las ms indicadas para definir propiedades por defecto.
Aunque no siempre el valor devuelto debe ser un elemento de una coleccin o array,
ya que podemos usar las propiedades predeterminadas para acceder a los
miembros de una clase "normal", de forma que se devuelva un valor segn el
parmetro indicado, esto nos permitira, por ejemplo, acceder a los miembros de la
clase desde un bucle )or. Si definimos una propiedad predeterminada como en el
siguiente cdigo:
?!blic Class Artic!lo
?!blic Descri2ciSn As String
?!blic ?recio$enta As Decimal
?!blic Gistencias As Decimal
De8a!lt ?!blic "ea%0nl- ?ro2ert- Item(,-$al in%eG As Integer)
As String
;et
Select Case in%eG
Case 0
"et!rn Descri2ciSn
Case 1
69
"et!rn ?recio$enta/1oString
Case 2
"et!rn Gistencias/1oString
Case lse
"et!rn ""
n% Select
n% ;et
n% ?ro2ert-
n% Class
La podemos usar de esta forma:
)or i As Integer = 0 1o 2
Console/<rite'ine( art(i) )
AeGt

Resumiendo:
Las propiedades predeterminadas en Visual Basic 2005 siempre deben tener un
parmetro, para que su uso se asemeje a un array, es decir, se use como indizador
de la clase. Por convencin, cuando se usan como indizador, el nombre de la
propiedad predeterminada suele ser Item.

Interfaces
Las interfaces son un elemento bastante importante en .NET Framework, ya que de
hecho se utiliza con bastante frecuencia, en esta leccin veremos que son las
interfaces y como utilizarlas en nuestros proyectos, tambin veremos que papel
juegan en .NET y cmo aplicar algunas de las definidas en la biblioteca base.

78u0 es una interfa*9
Las interfaces son una forma especial de una clase, aunque la diferencia principal
con las clases es que las interfaces no contienen cdigo ejecutable, solo definen los
miembros.
70
Para entenderlo mejor, veamos las interfaces desde el punto de vista de Visual Basic
6.0.
En Visual Basic 6.0, cuando definimos una clase, realmente estamos haciendo dos
cosas:
1- Definiendo una interfaz con cada uno de los miembros que la clase contiene:
mtodos, propiedades, eventos, etc.
2- Definiendo el cdigo a utilizar por cada uno de esos miembros.
Desde ese punto de vista, podemos decir que una interfaz define cada uno de los
miembros de una clase, es decir, que tipo de mtodo es, si los mtodos tienen
parmetros, cuantos y de que tipos son, que propiedades o eventos define la clase,
etc.
Por tanto, podemos decir que la interfaz de una clase indica los miembros que dicha
clase expone, y como hemos indicado anteriormente, cuando en VB6 definimos una
clase, tambin estamos definiendo una interfaz, de hecho en Visual Basic 6.0 no hay
forma de definir interfaces como algo independiente de una clase; cuando queremos
definir una interfaz en VB6, lo ms que podemos hacer es definir una clase sin
cdigo ejecutable.
Pero Visual Basic 2005, va an ms lejos, ya que las interfaces las definimos de
forma independiente de las clases. Es ms, cuando definimos una clase NO estamos
definiendo una interfaz.
Para definir una interfaz en VB2005 tenemos que usar la instruccin Interface
seguida del nombre y acabar la declaracin con %nd Interface:
?!blic Inter8ace IAnimal
4///
n% Inter8ace


Nota3
Segn las indicaciones de nomenclatura de .NET Framework, se
recomienda que todas las interfaces empiecen con una I mayscula
seguida del nombre al que hacer referencia la interfaz.


71
78u0 contiene una interfa*9
Al principio de esta leccin hemos comentado que las interfaces no contienen
cdigo, solo define los miembros que contiene. Esa definicin la haremos como
cualquier otra, con la diferencia de que no incluimos ningn cdigo, solo la "firma" o
el prototipo de cada uno de esos miembros.
En el siguiente cdigo definimos una interfaz que contiene los cuatros tipos de
miembros tpicos de cualquier clase:
?!blic Inter8ace I?r!eba
S!b Hostrar()
)!nction Sal!%o(,-$al nombre As String) As String
?ro2ert- Aombre() As String
5ent DatosCambia%os()
n% Inter8ace
El primer miembro de esta interfaz, es un mtodo de tipo Sub que no recibe
parmetros.
El siguiente mtodo es una funcin que devuelve un valor de tipo String y recibe un
parmetro tambin de tipo cadena.
A continuacin definimos una propiedad que devuelve una cadena.
Por ltimo, definimos un evento.
Como podemos observar, lo nico que tenemos que hacer es indicar el tipo de
miembro y si recibe o no algn parmetro o argumento.
Dos cosas importantes sobre las interfaces:
1- No se pueden definir campos.
2- Los miembros de las interfaces siempre son pblicos, tal como indicbamos en la
tabla 1.3.

:na interfa* es un contrato
Siempre que leemos sobre las interfaces, lo primero con lo que nos solemos
encontrar es que una interfa. es un contrato. Veamos que nos quieren decir con esa
frase.
Tal como acabamos de ver, las interfaces solo definen los miembros, pero no el
cdigo a usar en cada uno de ellos, esto es as precisamente porque el papel que
juegan las interfaces es el de solo indicar que es lo que una clase o estructura
puede, o mejor dicho, debe implementar.
Si en una clase indicamos que queremos "implementar" una interfaz, esa clase debe
definir cada uno de los miembros que la interfaz expone. De esta forma nos
72
aseguramos de que si una clase implementa una interfaz, tambin implementa
todos los miembros definidos en dicha interfaz.
Cuando una clase implementa una interfaz est firmando un contrato con el que se
compromete a definir todos los miembros que la clase define, de hecho el propio
compilador nos obliga a hacerlo.

'as interfaces y el polimorfismo
Como comentamos anteriormente, el polimorfismo es una caracterstica que nos
permite acceder a los miembros de un objeto sin necesidad de tener un
conocimiento exacto de ese objeto (o de la clase a partir del que se ha instanciado),
lo nico que tenemos que saber es que ese objeto tiene ciertos mtodos (u otros
miembros) a los que podemos acceder. Tambin hemos comentado que las
interfaces representan un contrato entre las clases que las implementan, por tanto
las interfaces pueden ser, (de hecho lo son), un medio para poner en prctica esta
caracterstica de la programacin orientada a objetos. Si una clase implementa una
interfaz, esa clase tiene todos los miembros de la interfaz, por tanto podemos
acceder a esa clase, que en principio pude sernos desconocida, desde un objeto del
mismo tipo que la interfaz.

:sar una interfa* en una clase
Para poder utilizar una interfaz en una clase, o dicho de otra forma: para
"implementar" los miembros expuestos por una interfaz en una clase debemos
hacerlo mediante la instruccin Implements seguida del nombre de la interfaz:
?!blic Class ?r!eba
Im2lements I?r!eba
Y como comentbamos, cualquier clase que implemente una interfaz debe definir
cada uno de los miembros de esa interfaz, por eso es el propio Visual Basic el
encargado de crear automticamente los mtodos y propiedades que la interfaz
implementa, aunque solo inserta el "prototipo" de cada uno de esos miembros,
dejando para nosotros el trabajo de escribir el cdigo.
Usando la definicin de la interfaz I8rue#a que vimos antes, el cdigo que aadir
VB ser el siguiente:
?!blic Class ?r!eba
Im2lements I?r!eba
73
?!blic 5ent DatosCambia%os() Im2lements
I?r!eba/DatosCambia%os
?!blic S!b Hostrar() Im2lements I?r!eba/Hostrar
n% S!b
?!blic ?ro2ert- Aombre() As String Im2lements I?r!eba/Aombre
;et
n% ;et
Set(,-$al 5al!e As String)
n% Set
n% ?ro2ert-
?!blic )!nction Sal!%o(,-$al nombre As String) As String +
Im2lements I?r!eba/Sal!%o
n% )!nction
n% Class
Como podemos apreciar, no solo ha aadido las definiciones de cada miembro de la
interfaz, sino que tambin aade cdigo extra a cada uno de esos miembros: la
instruccin Implements seguida del nombre de la interfaz y el miembro al que se
har referencia.

Nota3
Si el lector antes ha utilizado las interfaces en VB6, esto no le resultar
extrao, ya que en ese lenguaje, cuando implementamos una interfaz
tambin se crean automticamente las definiciones de los miembros
que contiene la interfaz, aunque el formato utilizado por VB6 es:
<Nombre de la interfaz> <guin bajo> <nombre del mtodo>, por
ejemplo: Private Sub IPrueba_Mostrar().
74

La utilidad de que en cada uno de los miembros se indique expresamente el mtodo
al que se hace referencia, es que podemos usar nombres diferentes al indicado en
la interfaz. Por ejemplo, si implementamos esta interfaz en una clase que solo
utilizar la impresora, al mtodo Mostrar lo podramos llamar Imprimir que sera
ms adecuado, en ese caso simplemente cambiamos el nombre del mtodo de la
clase para que implemente el mtodo Mostrar de la interfaz:
?!blic S!b Im2rimir() Im2lements I?r!eba/Hostrar
n% S!b
De esta forma, aunque en la clase se llame de forma diferente, realmente hace
referencia al mtodo de la interfaz.

Acceder a los miembros implementados
Una vez que tenemos implementada una interfaz en nuestra clase, podemos
acceder a esos miembros de forma directa, es decir, usando un objeto creado a
partir de la clase:
Dim 2r!eba1 As AeJ ?r!eba
2r!eba1/Hostrar()
O bien de forma indirecta, por medio de una variable del mismo tipo que la interfaz:
Dim 2r!eba1 As AeJ ?r!eba
Dim inter8a&1 As I?r!eba
inter8a&1 = 2r!eba1
inter8a&1/Hostrar()
Qu ha ocurre aqu?
Como ya comentamos anteriormente, cuando asignamos variables por referencia,
realmente lo que asignamos son referencias a los objetos creados en la memoria,
por tanto la variable interfa@$ est haciendo referencia al mismo objeto que
prue#a$, aunque esa variable solo tendr acceso a los miembros de la clase
75
Prueba que conoce, es decir, los miembros definidos en I8rue#a.
Si la clase define otros miembros que no estn en la interfaz, la variable interfa@$
no podr acceder a ellos.

Saber si un obeto implementa una interfa*
Si las interfaces sirven para acceder de forma annima a los mtodos de un objeto,
es normal que en Visual Basic tengamos algn mecanismo para descubrir si un
objeto implementa una interfaz.
Para realizar esta comprobacin podemos usar en una expresin If5T"en la
instruccin TypeOf... Is, de forma que si la variable indicada despus de TypeOf
contiene el tipo especificado despus de Is, la condicin se cumple:
I8 1-2e08 2r!eba1 Is I?r!eba 1hen
inter8a&1 = 2r!eba1
inter8a&1/Hostrar()
n% I8
De esta forma nos aseguramos de que el cdigo se ejecutar solamente si la
variable prue#a$ contiene una definicin de la interfaz I8rue#a.

-mplementaci(n de m)ltiples interfaces
En Visual Basic 2005, una misma clase puede implementar ms de una interfaz.
Para indicar que implementamos ms de una interfaz podemos hacerlo de dos
formas:
1- Usando nuevamente la instruccin Implements seguida del nombre de la
interfaz:
?!blic Class ?r!eba
Im2lements I?r!eba
Im2lements ICom2arable
2- Indicando las otras interfaces en la misma instruccin Implements, pero
separndolas con comas:
?!blic Class ?r!eba
76
Im2lements I?r!eba, ICom2arable
De cualquiera de las dos formas es vlido implementar ms de una interfaz, aunque
en ambos casos siempre debemos definir los miembros de cada una de esas
interfaces.

%)ltiple implementaci(n de un mismo miembro
Como acabamos de comprobar, una misma clase puede implementar ms de una
interfaz, y esto nos puede causar una duda:
Qu ocurre si dos interfaces definen un mtodo que es idntico en ambas?
En principio, no habra problemas, ya que el propio Visual Basic creara dos mtodos
con nombres diferentes y a cada uno le asignara la implementacin de ese mtodo
definido en cada interfaz.
Por ejemplo, si tenemos otra interfaz que define el mtodo Mostrar y la
implementamos en la clase 8rue#a, la declaracin podra quedar de esta forma:
?!blic Inter8ace IHostrar
S!b Hostrar()
n% Inter8ace

?!blic S!b Hostrar1() Im2lements IHostrar/Hostrar
n% S!b
Aunque si ambos mtodos hacen lo mismo, en este ejemplo mostrar algo,
podramos hacer que el mismo mtodo de la clase sirva para implementar el de las
dos interfaces:
?!blic S!b Hostrar() Im2lements I?r!eba/Hostrar, IHostrar/Hostrar
n% S!b
Es decir, lo nico que tendramos que hacer es indicar la otra implementacin
separndola con una coma.


77
7"(nde podemos implementar las interfaces9
Para ir acabando este tema nos queda por saber, entre otras cosas, dnde podemos
implementar las interfaces, es decir, en que tipos de datos podemos usar
Implements.
La implementacin de interfaces la podemos hacer en las clases (Class), estructuras
(Structure) y en otras interfaces (Interface).
Debido a que una interfaz puede implementar otras interfaces, si en una clase
implementamos una interfaz que a su vez implementa otras, esa clase tendr
definidas cada una de las interfaces, lo mismo ocurre con una clase que "se derive"
de otra clase que implementa alguna interfaz, la nueva clase tambin incorporar
esa interfaz.

Nota3
Cuando una interfaz implementa otras interfaces, stas no se pueden
indicar mediante Implements, en lugar de usar esa instruccin
debemos usar Inherits.
Public Interface IPrueba2
Inherits IMostrar


Si en una clase implementamos una interfaz que a su vez implementa otras
interfaces, esa clase tendr definiciones de todos los miembros de todas las
interfaces, por ejemplo, si tenemos la siguiente definicin de la interfaz I8rue#a2
que "implementa" la interfaz IMostrar:
?!blic Inter8ace I?r!eba2
Inherits IHostrar
)!nction Sal!%o(,-$al nombre As String) As String
?ro2ert- Aombre() As String
5ent DatosCambia%os()
n% Inter8ace
Y la clase 8rue#a2 implementa I8rue#a2, la definicin de los miembros quedara
de la siguiente forma:
?!blic Class ?r!eba2
78
Im2lements I?r!eba2
?!blic S!b Hostrar() Im2lements IHostrar/Hostrar
n% S!b
?!blic 5ent DatosCambia%os() Im2lements
I?r!eba2/DatosCambia%os
?!blic ?ro2ert- Aombre() As String Im2lements I?r!eba2/Aombre
;et
n% ;et
Set(,-$al 5al!e As String)
n% Set
n% ?ro2ert-
?!blic )!nction Sal!%o(,-$al nombre As String) As String +
Im2lements I?r!eba2/Sal!%o
n% )!nction
n% Class
En este cdigo, el mtodo Mostrar se indica mediante la interfaz IMostrar, pero
tambin se puede hacer por medio de I8rue#a2.Mostrar, ya que I8rue#a2
tambin lo implementa (o hereda).
Si dejamos que Visual Basic cree los miembros, no tendremos problemas a la hora
de definirlos. Pero si lo hacemos manualmente, aunque dentro del IDE de Visual
Basic, ste nos ayuda indicndonos que interfaces implementamos y qu miembros
son los que se adecuan a la declaracin que estamos usando, tal como podemos
comprobar en la figura 1.02.16:
79
Fi'ura $.02.$" IntelliSense solo muestra los mHtodos &ue me(or se
adecuan a la declaracin


:n eemplo pr&ctico usando una interfa* de .NET
Tal como comentamos al principio, el propio .NET est "plagado" de interfaces, cada
una de ellas tiene un fin concreto, por ejemplo, si queremos definir una clase que
pueda ser clasificada por el propio .NET, esa clase debe implementar la interfaz
IComparable, ya que el mtodo Sort, (de la clase que contiene los elementos del
tipo definido por nosotros), que es el encargado de clasificar los elementos, har
una llamada al mtodo IComparable.CompareTo de cada uno de los objetos que
queremos clasificar, por tanto, si la clase no ha definido esa interfaz, no podremos
clasificar los elementos que contenga.
En el siguiente cdigo tenemos la definicin de una clase llamada Empleado que
implementa la interfaz IComparable y en el mtodo CompareTo hace la
comprobacin de que objeto es mayor o menor, si el de la propia clase o el indicado
en el parmetro de esa funcin:
?!blic Class m2lea%o
Im2lements ICom2arable
?!blic Aombre As String
?!blic S!b AeJ(,-$al nombre As String)
He/Aombre = nombre
n% S!b
4 Si el ob#eto es %el ti2o m2lea%o, com2aramos los nombres/
4 Si no es %el ti2o m2lea%o, %e5ol5emos !n cero
4 I!e signi8ica I!e los %os ob#etos son ig!ales/
?!blic )!nction Com2are1o(,-$al ob# As 0b#ect) As Integer +
80
Im2lements S-stem/ICom2arable/Com2are1o
I8 1-2e08 ob# Is m2lea%o 1hen
Dim e1 As m2lea%o = C1-2e(ob#, m2lea%o)
"et!rn String/Com2are(He/Aombre, e1/Aombre)
lse
"et!rn 0
n% I8
n% )!nction
n% Class
En el mtodo CompareTo hacemos una comprobacin de que el objeto con el que
debemos realizar la comparacin es del tipo Empleado, en ese caso convertimos el
objeto pasado en uno del tipo Empleado y comparamos los nombres.
Si el objeto que recibe el mtodo no es del tipo Empleado, devolvemos un cero,
para indicar que no haga ninguna clasificacin, ya que ese valor indica que los dos
objetos son iguales.
Esta comparacin no es estrictamente necesaria, ya que si no indicamos el valor
que debe devolver una funcin, devolver un valor cero, al menos en este caso, ya
que el tipo a devolver es un nmero entero.
Esta clase la podemos usar de esta forma:
4 Fna colecciSn %e %atos %el ti2o m2lea%o/
Dim em2lea%os As AeJ S-stem/Collections/;eneric/'ist(08 m2lea%o)
4 ATa%imos 5arios em2lea%os a la colecciSn/
em2lea%os/A%%(AeJ m2lea%o("?e2e"))
em2lea%os/A%%(AeJ m2lea%o(",ernar%o"))
em2lea%os/A%%(AeJ m2lea%o("@!an"))
em2lea%os/A%%(AeJ m2lea%o("Ana"))
4 Clasi8icamos los em2lea%os %e la colecciSn/
em2lea%os/Sort()
81
4 Hostramos los %atos !na 5e& clasi8ica%os/
)or ach e1 As m2lea%o In em2lea%os
Console/<rite'ine(e1/Aombre)
AeGt

Interfaces
Las interfaces son un elemento bastante importante en .NET Framework, ya que de
hecho se utiliza con bastante frecuencia, en esta leccin veremos que son las
interfaces y como utilizarlas en nuestros proyectos, tambin veremos que papel
juegan en .NET y cmo aplicar algunas de las definidas en la biblioteca base.

78u0 es una interfa*9
Las interfaces son una forma especial de una clase, aunque la diferencia principal
con las clases es que las interfaces no contienen cdigo ejecutable, solo definen los
miembros.
Para entenderlo mejor, veamos las interfaces desde el punto de vista de Visual Basic
6.0.
En Visual Basic 6.0, cuando definimos una clase, realmente estamos haciendo dos
cosas:
1- Definiendo una interfaz con cada uno de los miembros que la clase contiene:
mtodos, propiedades, eventos, etc.
2- Definiendo el cdigo a utilizar por cada uno de esos miembros.
Desde ese punto de vista, podemos decir que una interfaz define cada uno de los
miembros de una clase, es decir, que tipo de mtodo es, si los mtodos tienen
parmetros, cuantos y de que tipos son, que propiedades o eventos define la clase,
etc.
Por tanto, podemos decir que la interfaz de una clase indica los miembros que dicha
clase expone, y como hemos indicado anteriormente, cuando en VB6 definimos una
clase, tambin estamos definiendo una interfaz, de hecho en Visual Basic 6.0 no hay
forma de definir interfaces como algo independiente de una clase; cuando queremos
definir una interfaz en VB6, lo ms que podemos hacer es definir una clase sin
cdigo ejecutable.
Pero Visual Basic 2005, va an ms lejos, ya que las interfaces las definimos de
forma independiente de las clases. Es ms, cuando definimos una clase NO estamos
definiendo una interfaz.
Para definir una interfaz en VB2005 tenemos que usar la instruccin Interface
seguida del nombre y acabar la declaracin con %nd Interface:
82
?!blic Inter8ace IAnimal
4///
n% Inter8ace


Nota3
Segn las indicaciones de nomenclatura de .NET Framework, se
recomienda que todas las interfaces empiecen con una I mayscula
seguida del nombre al que hacer referencia la interfaz.


78u0 contiene una interfa*9
Al principio de esta leccin hemos comentado que las interfaces no contienen
cdigo, solo define los miembros que contiene. Esa definicin la haremos como
cualquier otra, con la diferencia de que no incluimos ningn cdigo, solo la "firma" o
el prototipo de cada uno de esos miembros.
En el siguiente cdigo definimos una interfaz que contiene los cuatros tipos de
miembros tpicos de cualquier clase:
?!blic Inter8ace I?r!eba
S!b Hostrar()
)!nction Sal!%o(,-$al nombre As String) As String
?ro2ert- Aombre() As String
5ent DatosCambia%os()
n% Inter8ace
El primer miembro de esta interfaz, es un mtodo de tipo Sub que no recibe
parmetros.
El siguiente mtodo es una funcin que devuelve un valor de tipo String y recibe un
parmetro tambin de tipo cadena.
A continuacin definimos una propiedad que devuelve una cadena.
Por ltimo, definimos un evento.
Como podemos observar, lo nico que tenemos que hacer es indicar el tipo de
miembro y si recibe o no algn parmetro o argumento.
83
Dos cosas importantes sobre las interfaces:
1- No se pueden definir campos.
2- Los miembros de las interfaces siempre son pblicos, tal como indicbamos en la
tabla 1.3.

:na interfa* es un contrato
Siempre que leemos sobre las interfaces, lo primero con lo que nos solemos
encontrar es que una interfa. es un contrato. Veamos que nos quieren decir con esa
frase.
Tal como acabamos de ver, las interfaces solo definen los miembros, pero no el
cdigo a usar en cada uno de ellos, esto es as precisamente porque el papel que
juegan las interfaces es el de solo indicar que es lo que una clase o estructura
puede, o mejor dicho, debe implementar.
Si en una clase indicamos que queremos "implementar" una interfaz, esa clase debe
definir cada uno de los miembros que la interfaz expone. De esta forma nos
aseguramos de que si una clase implementa una interfaz, tambin implementa
todos los miembros definidos en dicha interfaz.
Cuando una clase implementa una interfaz est firmando un contrato con el que se
compromete a definir todos los miembros que la clase define, de hecho el propio
compilador nos obliga a hacerlo.

'as interfaces y el polimorfismo
Como comentamos anteriormente, el polimorfismo es una caracterstica que nos
permite acceder a los miembros de un objeto sin necesidad de tener un
conocimiento exacto de ese objeto (o de la clase a partir del que se ha instanciado),
lo nico que tenemos que saber es que ese objeto tiene ciertos mtodos (u otros
miembros) a los que podemos acceder. Tambin hemos comentado que las
interfaces representan un contrato entre las clases que las implementan, por tanto
las interfaces pueden ser, (de hecho lo son), un medio para poner en prctica esta
caracterstica de la programacin orientada a objetos. Si una clase implementa una
interfaz, esa clase tiene todos los miembros de la interfaz, por tanto podemos
acceder a esa clase, que en principio pude sernos desconocida, desde un objeto del
mismo tipo que la interfaz.

:sar una interfa* en una clase
Para poder utilizar una interfaz en una clase, o dicho de otra forma: para
"implementar" los miembros expuestos por una interfaz en una clase debemos
hacerlo mediante la instruccin Implements seguida del nombre de la interfaz:
84
?!blic Class ?r!eba
Im2lements I?r!eba
Y como comentbamos, cualquier clase que implemente una interfaz debe definir
cada uno de los miembros de esa interfaz, por eso es el propio Visual Basic el
encargado de crear automticamente los mtodos y propiedades que la interfaz
implementa, aunque solo inserta el "prototipo" de cada uno de esos miembros,
dejando para nosotros el trabajo de escribir el cdigo.
Usando la definicin de la interfaz I8rue#a que vimos antes, el cdigo que aadir
VB ser el siguiente:
?!blic Class ?r!eba
Im2lements I?r!eba
?!blic 5ent DatosCambia%os() Im2lements
I?r!eba/DatosCambia%os
?!blic S!b Hostrar() Im2lements I?r!eba/Hostrar
n% S!b
?!blic ?ro2ert- Aombre() As String Im2lements I?r!eba/Aombre
;et
n% ;et
Set(,-$al 5al!e As String)
n% Set
n% ?ro2ert-
?!blic )!nction Sal!%o(,-$al nombre As String) As String +
Im2lements I?r!eba/Sal!%o
85
n% )!nction
n% Class
Como podemos apreciar, no solo ha aadido las definiciones de cada miembro de la
interfaz, sino que tambin aade cdigo extra a cada uno de esos miembros: la
instruccin Implements seguida del nombre de la interfaz y el miembro al que se
har referencia.

Nota3
Si el lector antes ha utilizado las interfaces en VB6, esto no le resultar
extrao, ya que en ese lenguaje, cuando implementamos una interfaz
tambin se crean automticamente las definiciones de los miembros
que contiene la interfaz, aunque el formato utilizado por VB6 es:
<Nombre de la interfaz> <guin bajo> <nombre del mtodo>, por
ejemplo: Private Sub IPrueba_Mostrar().

La utilidad de que en cada uno de los miembros se indique expresamente el mtodo
al que se hace referencia, es que podemos usar nombres diferentes al indicado en
la interfaz. Por ejemplo, si implementamos esta interfaz en una clase que solo
utilizar la impresora, al mtodo Mostrar lo podramos llamar Imprimir que sera
ms adecuado, en ese caso simplemente cambiamos el nombre del mtodo de la
clase para que implemente el mtodo Mostrar de la interfaz:
?!blic S!b Im2rimir() Im2lements I?r!eba/Hostrar
n% S!b
De esta forma, aunque en la clase se llame de forma diferente, realmente hace
referencia al mtodo de la interfaz.

Acceder a los miembros implementados
Una vez que tenemos implementada una interfaz en nuestra clase, podemos
acceder a esos miembros de forma directa, es decir, usando un objeto creado a
partir de la clase:
Dim 2r!eba1 As AeJ ?r!eba
2r!eba1/Hostrar()
86
O bien de forma indirecta, por medio de una variable del mismo tipo que la interfaz:
Dim 2r!eba1 As AeJ ?r!eba
Dim inter8a&1 As I?r!eba
inter8a&1 = 2r!eba1
inter8a&1/Hostrar()
Qu ha ocurre aqu?
Como ya comentamos anteriormente, cuando asignamos variables por referencia,
realmente lo que asignamos son referencias a los objetos creados en la memoria,
por tanto la variable interfa@$ est haciendo referencia al mismo objeto que
prue#a$, aunque esa variable solo tendr acceso a los miembros de la clase
Prueba que conoce, es decir, los miembros definidos en I8rue#a.
Si la clase define otros miembros que no estn en la interfaz, la variable interfa@$
no podr acceder a ellos.

Saber si un obeto implementa una interfa*
Si las interfaces sirven para acceder de forma annima a los mtodos de un objeto,
es normal que en Visual Basic tengamos algn mecanismo para descubrir si un
objeto implementa una interfaz.
Para realizar esta comprobacin podemos usar en una expresin If5T"en la
instruccin TypeOf... Is, de forma que si la variable indicada despus de TypeOf
contiene el tipo especificado despus de Is, la condicin se cumple:
I8 1-2e08 2r!eba1 Is I?r!eba 1hen
inter8a&1 = 2r!eba1
inter8a&1/Hostrar()
n% I8
De esta forma nos aseguramos de que el cdigo se ejecutar solamente si la
variable prue#a$ contiene una definicin de la interfaz I8rue#a.

87
-mplementaci(n de m)ltiples interfaces
En Visual Basic 2005, una misma clase puede implementar ms de una interfaz.
Para indicar que implementamos ms de una interfaz podemos hacerlo de dos
formas:
1- Usando nuevamente la instruccin Implements seguida del nombre de la
interfaz:
?!blic Class ?r!eba
Im2lements I?r!eba
Im2lements ICom2arable
2- Indicando las otras interfaces en la misma instruccin Implements, pero
separndolas con comas:
?!blic Class ?r!eba
Im2lements I?r!eba, ICom2arable
De cualquiera de las dos formas es vlido implementar ms de una interfaz, aunque
en ambos casos siempre debemos definir los miembros de cada una de esas
interfaces.

%)ltiple implementaci(n de un mismo miembro
Como acabamos de comprobar, una misma clase puede implementar ms de una
interfaz, y esto nos puede causar una duda:
Qu ocurre si dos interfaces definen un mtodo que es idntico en ambas?
En principio, no habra problemas, ya que el propio Visual Basic creara dos mtodos
con nombres diferentes y a cada uno le asignara la implementacin de ese mtodo
definido en cada interfaz.
Por ejemplo, si tenemos otra interfaz que define el mtodo Mostrar y la
implementamos en la clase 8rue#a, la declaracin podra quedar de esta forma:
?!blic Inter8ace IHostrar
S!b Hostrar()
n% Inter8ace

?!blic S!b Hostrar1() Im2lements IHostrar/Hostrar
88
n% S!b
Aunque si ambos mtodos hacen lo mismo, en este ejemplo mostrar algo,
podramos hacer que el mismo mtodo de la clase sirva para implementar el de las
dos interfaces:
?!blic S!b Hostrar() Im2lements I?r!eba/Hostrar, IHostrar/Hostrar
n% S!b
Es decir, lo nico que tendramos que hacer es indicar la otra implementacin
separndola con una coma.


7"(nde podemos implementar las interfaces9
Para ir acabando este tema nos queda por saber, entre otras cosas, dnde podemos
implementar las interfaces, es decir, en que tipos de datos podemos usar
Implements.
La implementacin de interfaces la podemos hacer en las clases (Class), estructuras
(Structure) y en otras interfaces (Interface).
Debido a que una interfaz puede implementar otras interfaces, si en una clase
implementamos una interfaz que a su vez implementa otras, esa clase tendr
definidas cada una de las interfaces, lo mismo ocurre con una clase que "se derive"
de otra clase que implementa alguna interfaz, la nueva clase tambin incorporar
esa interfaz.

Nota3
Cuando una interfaz implementa otras interfaces, stas no se pueden
indicar mediante Implements, en lugar de usar esa instruccin
debemos usar Inherits.
Public Interface IPrueba2
Inherits IMostrar


Si en una clase implementamos una interfaz que a su vez implementa otras
interfaces, esa clase tendr definiciones de todos los miembros de todas las
89
interfaces, por ejemplo, si tenemos la siguiente definicin de la interfaz I8rue#a2
que "implementa" la interfaz IMostrar:
?!blic Inter8ace I?r!eba2
Inherits IHostrar
)!nction Sal!%o(,-$al nombre As String) As String
?ro2ert- Aombre() As String
5ent DatosCambia%os()
n% Inter8ace
Y la clase 8rue#a2 implementa I8rue#a2, la definicin de los miembros quedara
de la siguiente forma:
?!blic Class ?r!eba2
Im2lements I?r!eba2
?!blic S!b Hostrar() Im2lements IHostrar/Hostrar
n% S!b
?!blic 5ent DatosCambia%os() Im2lements
I?r!eba2/DatosCambia%os
?!blic ?ro2ert- Aombre() As String Im2lements I?r!eba2/Aombre
;et
n% ;et
Set(,-$al 5al!e As String)
n% Set
n% ?ro2ert-
90
?!blic )!nction Sal!%o(,-$al nombre As String) As String +
Im2lements I?r!eba2/Sal!%o
n% )!nction
n% Class
En este cdigo, el mtodo Mostrar se indica mediante la interfaz IMostrar, pero
tambin se puede hacer por medio de I8rue#a2.Mostrar, ya que I8rue#a2
tambin lo implementa (o hereda).
Si dejamos que Visual Basic cree los miembros, no tendremos problemas a la hora
de definirlos. Pero si lo hacemos manualmente, aunque dentro del IDE de Visual
Basic, ste nos ayuda indicndonos que interfaces implementamos y qu miembros
son los que se adecuan a la declaracin que estamos usando, tal como podemos
comprobar en la figura 1.02.16:
Fi'ura $.02.$" IntelliSense solo muestra los mHtodos &ue me(or se
adecuan a la declaracin


:n eemplo pr&ctico usando una interfa* de .NET
Tal como comentamos al principio, el propio .NET est "plagado" de interfaces, cada
una de ellas tiene un fin concreto, por ejemplo, si queremos definir una clase que
pueda ser clasificada por el propio .NET, esa clase debe implementar la interfaz
IComparable, ya que el mtodo Sort, (de la clase que contiene los elementos del
tipo definido por nosotros), que es el encargado de clasificar los elementos, har
una llamada al mtodo IComparable.CompareTo de cada uno de los objetos que
queremos clasificar, por tanto, si la clase no ha definido esa interfaz, no podremos
clasificar los elementos que contenga.
En el siguiente cdigo tenemos la definicin de una clase llamada Empleado que
implementa la interfaz IComparable y en el mtodo CompareTo hace la
comprobacin de que objeto es mayor o menor, si el de la propia clase o el indicado
en el parmetro de esa funcin:
?!blic Class m2lea%o
Im2lements ICom2arable
91
?!blic Aombre As String
?!blic S!b AeJ(,-$al nombre As String)
He/Aombre = nombre
n% S!b
4 Si el ob#eto es %el ti2o m2lea%o, com2aramos los nombres/
4 Si no es %el ti2o m2lea%o, %e5ol5emos !n cero
4 I!e signi8ica I!e los %os ob#etos son ig!ales/
?!blic )!nction Com2are1o(,-$al ob# As 0b#ect) As Integer +
Im2lements S-stem/ICom2arable/Com2are1o
I8 1-2e08 ob# Is m2lea%o 1hen
Dim e1 As m2lea%o = C1-2e(ob#, m2lea%o)
"et!rn String/Com2are(He/Aombre, e1/Aombre)
lse
"et!rn 0
n% I8
n% )!nction
n% Class
En el mtodo CompareTo hacemos una comprobacin de que el objeto con el que
debemos realizar la comparacin es del tipo Empleado, en ese caso convertimos el
objeto pasado en uno del tipo Empleado y comparamos los nombres.
Si el objeto que recibe el mtodo no es del tipo Empleado, devolvemos un cero,
para indicar que no haga ninguna clasificacin, ya que ese valor indica que los dos
objetos son iguales.
Esta comparacin no es estrictamente necesaria, ya que si no indicamos el valor
que debe devolver una funcin, devolver un valor cero, al menos en este caso, ya
que el tipo a devolver es un nmero entero.
Esta clase la podemos usar de esta forma:
4 Fna colecciSn %e %atos %el ti2o m2lea%o/
92
Dim em2lea%os As AeJ S-stem/Collections/;eneric/'ist(08 m2lea%o)
4 ATa%imos 5arios em2lea%os a la colecciSn/
em2lea%os/A%%(AeJ m2lea%o("?e2e"))
em2lea%os/A%%(AeJ m2lea%o(",ernar%o"))
em2lea%os/A%%(AeJ m2lea%o("@!an"))
em2lea%os/A%%(AeJ m2lea%o("Ana"))
4 Clasi8icamos los em2lea%os %e la colecciSn/
em2lea%os/Sort()
4 Hostramos los %atos !na 5e& clasi8ica%os/
)or ach e1 As m2lea%o In em2lea%os
Console/<rite'ine(e1/Aombre)
AeGt

Mane(o de e;cepciones
En Visual Basic 2005 el tratamiento de errores (excepciones) ha cambiado con
respecto a como lo hacemos en Visual Basic 6.0, ahora podemos usar un
tratamiento de excepciones estructurado, de esta forma podemos detectar los
errores que se produzcan en nuestras aplicaciones de una forma ms "ordenada".
En Visual Basic 6.0 la nica forma de detectar errores es usando On %rror. Esta
forma no estructurada de tratar los errores se sigue soportando en Visual Basic
2005, pero a todas luces no es la forma recomendada, si bien es cierto que
debemos adaptar nuestra mente al formato estructurado, ya que en un principio nos
parecer que no es tan efectivo como On %rror.
En esta leccin veremos cmo tratar los errores de forma estructurada, ya que el
"viejo" On %rror sigue funcionando de la misma forma que en VB6.

%aneo de e;cepciones no estructuradas
Como hemos comentado, en Visual Basic 2005 tambin podemos usar el "viejo"
sistema de tratamientos de errores, es decir, el "clsico" On %rror... que ahora se
93
llama tratamiento de errores no estructurados. La forma de utilizar On %rror es la
misma que en Visual Basic 6.0, por tanto no vamos a entrar en detalles de cmo
usar esta forma de interceptar errores, solo aclarar un par de cosas que debemos
tener en cuenta:
La primera es: intentar no usar esta forma de detectar errores, es preferible,
aunque al principio cueste adaptarse, utilizar los errores estructurados.
La segunda es que no podemos usar los dos sistemas al mismo tiempo, por lo
menos en un mismo mtodo o propiedad, o utilizamos On %rror o utilizamos
Try5Catc". De todas formas, si utilizamos el IDE (entorno integrado) de Visual
Basic, ser el propio compilador el que nos avise cuando mezclemos las dos formas
de detectar los errores.

%aneo de e;cepciones estructuradas
Las excepciones en Visual Basic 2005 las podemos controlar usando las
instrucciones Try 5 Catc" 5 )inally. Estas instrucciones realmente son bloques de
instrucciones, al estilo de If 5 %lse.
Cuando queramos controlar una parte del cdigo que puede producir un error lo
incluimos dentro del bloque Try, si se produce un error, ste lo podemos detectar en
el bloque Catc", por ltimo, independientemente de que se produzca o no una
excepcin, podemos ejecutar el cdigo que incluyamos en el bloque )inally, para
indicar el final del bloque de control de excepciones lo haremos con %nd Try.
Cuando creamos una estructura de control de excepciones no estamos obligados a
usar los tres bloques, aunque el primero: Try si es necesario, ya que es el que le
indica al compilador que tenemos intencin de controlar los errores que se
produzcan. Por tanto podemos crear un "manejador" de excepciones usando los tres
bloques, usando Try y Catc" o usando Try y )inally.
Veamos ahora con ms detalle cada uno de estos bloques y que es lo que podemos
hacer en cada uno de ellos.
#loque $ry
En este bloque incluiremos el cdigo en el que queremos comprobar los errores.
El cdigo a usar ser un cdigo normal, es decir, no tenemos que hacer nada en
especial, ya que en el momento que se produzca el error se usar (si hay) el cdigo
del bloque Catc".
#loque Catc%
Si se produce una excepcin, sta la capturamos en un bloque Catc".
En el bloque Catc" podemos indicar que tipo de excepcin queremos capturar, para
ello usaremos una variable de tipo %&ception, la cual pude ser del tipo de error
especfico que queremos controlar o de un tipo genrico.
94
Por ejemplo, si sabemos que nuestro cdigo puede producir un error al trabajar con
ficheros, podemos usar un cdigo como este:
1r-
4 cS%igo 2ara traba#ar con 8icheros, etc/
Catch eG As S-stem/I0/I0Gce2tion
4 el cS%igo a e#ec!tar c!an%o se 2ro%!&ca ese error
n% 1r-
Si nuestra intencin es capturar todos los errores que se produzcan, es decir, no
queremos hacer un filtro con errores especficos, podemos usar la clase %&ception
como tipo de excepcin a capturar. La clase %&ception es la ms genrica de todas
las clases para manejo de excepciones, por tanto capturar todas las excepciones
que se produzcan.
1r-
4 cS%igo I!e I!eremos controlar
Catch eG As Gce2tion
4 el cS%igo a e#ec!tar c!an%o se 2ro%!&ca c!alI!ier error
n% 1r-
Aunque si no vamos usar la variable indicada en el bloque Catc", pero queremos
que no se detenga la aplicacin cuando se produzca un error, podemos hacerlo de
esta forma:
1r-
4 cS%igo I!e I!eremos controlar
Catch
4 el cS%igo a e#ec!tar c!an%o se 2ro%!&ca c!alI!ier error
n% 1r-

&arias capturas de errores en un mismo bloque $ry'Catc%
En un mismo Try podemos capturar diferentes tipos de errores, para ello podemos
incluir varios bloques Catc", cada uno de ellos con un tipo de excepcin diferente.
Es importante tener en cuenta que cuando se produce un error y usamos varios
bloques Catc", Visual Basic buscar la captura que mejor se adapte al error que se
95
ha producido, pero siempre lo har examinando los diferentes bloques Catc" que
hayamos indicado empezando por el indicado despus del bloque Try, por tanto
deberamos poner las ms genricas al final, de forma que siempre nos aseguremos
de que las capturas de errores ms especficas se intercepten antes que las
genricas.
valuacin condicional en un bloque Catc%
Adems de indicar la excepcin que queremos controlar, en un bloque Catc"
podemos aadir la clusula 4"en para evaluar una expresin. Si la evaluacin de la
expresin indicada despus de 4"en devuelve un valor verdadero, se procesar el
bloque Catc", en caso de que devuelva un valor falso, se ignorar esa captura de
error.
Esto nos permite poder indicar varios bloques Catc" que detecten el mismo error,
pero cada una de ellas pueden tener diferentes expresiones indicadas con 4"en.
En el siguiente ejemplo, se evala el bloque Catc" solo cuando el valor de la
variable y es cero, en otro caso se utilizar el que no tiene la clusula 4"en:
Dim G, -, r As Integer
1r-
G = CInt(Console/"ea%'ine())
- = CInt(Console/"ea%'ine())
r = G U -
Console/<rite'ine("l res!lta%o esD =0>", r)
Catch eG As Gce2tion <hen - = 0
Console/<rite'ine("Ao se 2!e%e %i5i%ir 2or cero/")
Catch eG As Gce2tion
Console/<rite'ine(eG/Hessage)
n% 1r-

#loque (inally
En este bloque podemos indicar las instrucciones que queremos que se ejecuten, se
produzca o no una excepcin. De esta forma nos aseguramos de que siempre se
ejecutar un cdigo, por ejemplo para liberar recursos, se haya producido un error o
no.

96
Nota3
Hay que tener en cuenta de que incluso si usamos Exit Try para salir
del bloque de control de errores, se ejecutar el cdigo indicado en el
bloque Finally.


Captura de errores no controlados
Como es lgico, si no controlamos las excepciones que se puedan producir en
nuestras aplicaciones, estas sern inicialmente controladas por el propio runtime
de .NET, en estos casos la aplicacin se detiene y se muestra el error al usuario.
Pero esto es algo que no deberamos consentir, por tanto siempre deberamos
detectar todos los errores que se produzcan en nuestras aplicaciones, pero a pesar
de que lo intentemos, es muy probable que no siempre podamos conseguirlo.
Por suerte, en Visual Basic 2005 tenemos dos formas de interceptar los errores no
controlados:
La primera es iniciando nuestra aplicacin dentro de un bloque Try5Catc", de esta
forma, cuando se produzca el error, se capturar en el bloque Catc".
La segunda forma de interceptar los errores no controlados es mediante el evento:
,n"andled%&ception, disponible por medio del objeto (y.*pplication.

Nota3
De los eventos nos ocuparemos en la siguiente leccin, pero como el
evento UnhandledException est directamente relacionado con la
captura de errores, lo mostramos en esta, aunque recomendamos al
lector que esta seccin la vuelva a leer despus de ver todo lo
relacionado con los eventos.

Este evento se "dispara" cuando se produce un error que no hemos interceptado,
por tanto podramos usarlo para prevenir que nuestra aplicacin se detenga o bien
para guardar en un fichero .lo' la causa de dicho error para posteriormente
actualizar el cdigo y prevenirlo. Ya que cuando se produce el evento
,n"andled%&ception, podemos averiguar el error que se ha producido e incluso
evitar que la aplicacin finalice. Esa informacin la obtenemos mediante
propiedades expuestas por el segundo parmetro del evento, en particular la
propiedad %&ception nos indicar el error que se ha producido y por medio de la
propiedad %&it*pplication podemos indicar si terminamos o no la aplicacin.

Nota3
Cuando ejecutamos una aplicacin desde el IDE (entorno de
97
desarrollo), los errores no controlados siempre se producen,
independientemente de que tengamos o no definida la captura de
errores desde el evento UnhandledException. Ese evento solo se
producir cuando ejecutemos la aplicacin fuera del IDE de Visual
Basic.

Introduccin
La forma que tienen nuestras clases y estructuras de comunicar que algo est
ocurriendo, es por medio de eventos. Los eventos no nos son desconocidos a los
desarrolladores de Visual Basic 6.0, ya que tambin existen y podemos definir en
ese lenguaje. En Visual Basic 2005 se siguen usando de la misma forma que en
VB6, aunque seguramente siempre que hemos ledo sobre el tema aparece la
palabra delegado. Y es que, aunque VB2005 nos oculte, o facilite, el trabajo con los
eventos, stos siempre estn relacionados con los delegados. En esta leccin
veremos que son los delegados y que relacin tienen con los eventos, tambin
veremos que podemos tener mayor control sobre cmo se interceptan los eventos e
incluso cmo y cuando se asocian los eventos en la aplicacin cliente, aunque
primero empezaremos viendo cmo declarar y utilizar eventos en nuestros tipos de
datos.

Eventos % dele'ados
Eventos
o Interceptar los eventos de los controles de un formulario
Interceptar eventos en Visual Basic 6.0
Interceptar eventos en Visual Basic 2005
o Asociar un evento con un control
o Formas de asociar los eventos con un control
1- Asociar el evento manualmente por medio de Handles
2- Asociar el evento desde la ventana de cdigo
3- Asociar el evento desde el diseador de formularios
o Asociar varios eventos a un mismo procedimiento
o Declarar una variable para asociar eventos con Handles
"efinir y producir eventos en una clase
o Definir eventos en una clase
o Producir un evento en nuestra clase
o Otra forma de asociar los eventos de una clase con un mtodo
Asociar eventos mediante AddHandler
Desasociar eventos mediante RemoveHandler
"elegados
o Qu ocurre cuando se asigna y se produce un evento?
o Qu papel juegan los delegados en todo este proceso?
98
o Definicin "formal" de delegado
o Utilizar un delegado para acceder a un mtodo
"efinir un evento bien informado

Introduccin
La forma que tienen nuestras clases y estructuras de comunicar que algo est
ocurriendo, es por medio de eventos. Los eventos no nos son desconocidos a los
desarrolladores de Visual Basic 6.0, ya que tambin existen y podemos definir en
ese lenguaje. En Visual Basic 2005 se siguen usando de la misma forma que en
VB6, aunque seguramente siempre que hemos ledo sobre el tema aparece la
palabra delegado. Y es que, aunque VB2005 nos oculte, o facilite, el trabajo con los
eventos, stos siempre estn relacionados con los delegados. En esta leccin
veremos que son los delegados y que relacin tienen con los eventos, tambin
veremos que podemos tener mayor control sobre cmo se interceptan los eventos e
incluso cmo y cuando se asocian los eventos en la aplicacin cliente, aunque
primero empezaremos viendo cmo declarar y utilizar eventos en nuestros tipos de
datos.

Eventos % dele'ados
Eventos
o Interceptar los eventos de los controles de un formulario
Interceptar eventos en Visual Basic 6.0
Interceptar eventos en Visual Basic 2005
o Asociar un evento con un control
o Formas de asociar los eventos con un control
1- Asociar el evento manualmente por medio de Handles
2- Asociar el evento desde la ventana de cdigo
3- Asociar el evento desde el diseador de formularios
o Asociar varios eventos a un mismo procedimiento
o Declarar una variable para asociar eventos con Handles
"efinir y producir eventos en una clase
o Definir eventos en una clase
o Producir un evento en nuestra clase
o Otra forma de asociar los eventos de una clase con un mtodo
Asociar eventos mediante AddHandler
Desasociar eventos mediante RemoveHandler
"elegados
o Qu ocurre cuando se asigna y se produce un evento?
o Qu papel juegan los delegados en todo este proceso?
o Definicin "formal" de delegado
99
o Utilizar un delegado para acceder a un mtodo
"efinir un evento bien informado

Eventos
En Visual Basic 2005 podemos usar los eventos de la misma forma que actualmente
lo hacemos en Visual Basic 6.0, al menos en lo que se refiere a la forma de
declararlos en nuestras clases y cmo "lanzarlos", ya que para interceptarlos en una
aplicacin esa forma ha cambiado un poco, pero como veremos, incluso puede ser
ms fcil definir los mtodos o procedimientos que utilizamos para interceptarlos.

-nterceptar los eventos de los controles de un formulario
Debido a que an no hemos visto el mdulo dedicado a las aplicaciones de
Windows, en las que se utilizan los "clsicos" formularios, no vamos a entrar en
detalles sobre cmo crear un formulario ni como aadir controles, etc., todo eso lo
veremos en el siguiente mdulo. Para simplificar las cosas, veremos simplemente la
diferencia de cmo se interceptan en un formulario de Visual Basic 6.0 y en otro de
la nueva versin de Visual Basic, pero como comentamos, sin entrar en demasiados
detalles.
Tanto en una versin como en otra de Visual Basic, la forma ms sencilla de asociar
el evento de un control con el cdigo que se usar, es haciendo doble-click en el
control; por ejemplo, si en nuestro formulario tenemos un botn, al hacer doble
pulsacin sobre l tendremos asociado el evento Clic6 del botn.

Interceptar eventos en &isual #asic )*+
En Visual Basic 6.0 el procedimiento que se crear tendr el siguiente aspecto:
?ri5ate S!b Comman%1+ClicQ()

n% S!b
Es decir, la "liga" entre un evento y el cdigo se indica usando la siguiente
nomenclatura:
<Nombre del control> <guin bajo> <nombre del evento>
De esta forma, el compilador sabe que asociamos ese evento del control al cdigo
indicado, de forma que cada vez que el usuario haga click sobre el botn, se
ejecutar dicho cdigo.
100

Interceptar eventos en &isual #asic ,++-
En Visual Basic 2005 aunque la forma de asignar los eventos predeterminados de
los controles es la misma, es decir, haciendo doble pulsacin en el control, la
declaracin del cdigo usado para interceptar el evento difiere un poco de VB6, tal
como podemos apreciar en el siguiente cdigo:
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As 0b#ect, ,-$al e As
5entArgs) +
Han%les ,!tton1/ClicQ
n% S!b
Lo primero que podemos notar es que en Visual Basic 2005 utiliza dos argumentos,
esto siempre es as en todos los eventos producidos por los controles. El primero
indica el control que produce el evento, (en nuestro ejemplo sera una referencia al
control Button1), y el segundo normalmente contiene informacin sobre el evento
que se produce, si el evento en cuestin no proporciona informacin extra, como es
el caso del evento Clic6, ese parmetro ser del tipo %ent*rgs. Sin embargo en
otros eventos, por ejemplo, los relacionados con el ratn (mouse), el segundo
argumento tendr informacin que nos puede resultar til, por ejemplo para saber
que botn se ha usado o cual es la posicin del cursor, en la figura 1.04.1 podemos
ver las propiedades relacionadas con el evento (ouse%ent*rgs:
Fi'ura $.0=.0$ 8ropiedades relacionadas con un evento del ratn
Como sabemos, en VB6, esa informacin se da usando argumentos extras en el
mtodo del evento, tal como podemos ver en el siguiente cdigo del evento
(ouse(oe de un botn llamado -ommand$:
?ri5ate S!b Comman%1+Ho!seHo5e(,!tton As Integer, Shi8t As
Integer, L As Single, M As Single)
101
n% S!b


Asociar un evento con un control
Siguiendo con el cdigo que intercepta el evento Clic6 de un botn, podemos
apreciar que el IDE de Visual Basic 2005 aade al final de la declaracin del
procedimiento de evento la instruccin 7andles seguida del control y el evento que
queremos interceptar: 5andles Button$.-lic!, esta la forma habitual de hacerlo
en VB2005, ya que, a diferencia de VB6, aqu no hay nombres "mgicos" para
asociar un evento con un control o incluso con el propio formulario, sino que esa
asociacin se hace de forma explcita y la forma que tiene Visual Basic 2005 de
hacerlo es usando la clusula 7andles.

Nota3
En Visual Basic 2005 el nombre del procedimiento de evento no est
relacionado con el evento, a diferencia de Visual Basic 6.0, en el que si
que hay una relacin directa entre el evento a interceptar y el nombre
del procedimiento.
Aunque por defecto, el nombre usado sera el equivalente al de VB6,
en la nueva versin puede tener cualquier nombre.

Tal como resaltamos en la nota anterior, en Visual Basic 2005, el nombre asociado a
un evento puede ser el que queramos, lo realmente importante es que indiquemos
la instruccin 7andles seguida del evento que queremos interceptar.

<ormas de asociar los eventos con un control
Cuando estamos trabajando con el diseador de formularios, tenemos tres formas
de asociar un evento con el cdigo correspondiente:
La forma ms sencilla es la expuesta anteriormente, es decir, haciendo doble click
en el control, esto har que se muestre el evento predeterminado del control. En el
caso del control Button, el evento predeterminado es el evento Clic6.
Si queremos escribir cdigo para otros eventos podemos hacerlo de tres formas,
aunque la primera que explicaremos no ser la ms habitual, ya que debemos saber
exactamente qu parmetros utiliza el evento.
102

./ Asociar el evento manualmente por medio de 0andles
Con esta forma, simplemente escribimos el nombre del procedimiento (puede ser
cualquier nombre), indicamos los dos argumentos que recibe: el primero siempre es
de tipo Object y el segundo depender del tipo de evento, y finalmente por medio
de la clusula 7andles lo asociamos con el control y el evento en cuestin.

,/ Asociar el evento desde la ventana de cdi"o
Al igual que en VB6, en Visual Basic 2005 tambin podemos seleccionar los eventos
disponibles de una lista desplegable. Esto lo haremos desde la ventana de cdigo.
En la parte superior derecha tenemos una la lista con los controles que hemos
aadido al formulario, seleccionamos el control que nos interese y en la lista que
hay a su izquierda tenemos los eventos que ese control produce. Por tanto podemos
seleccionar de esa lista de eventos el que nos interese interceptar, tal como
podemos ver en la figura 1.04.02
Fi'ura $.0=.02 *ista de eventos de un control
De esta forma el propio IDE ser el que cree el "esqueleto" del procedimiento de
evento usando los parmetros adecuados.

1/ Asociar el evento desde el dise2ador de formularios
La tercera forma de asociar un evento con un control, es hacerlo desde el diseador
de formularios. En la ventana de propiedades del control, (tal como podemos
apreciar en la figura 1.04.3), tenemos una lista con los eventos ms importantes de
cada control, seleccionando el evento de esa lista y haciendo doble-click en el que
nos interese, conseguiremos exactamente el mismo resultado que con el paso
anterior.
103
Fi'ura $.0=.0< Ventana de propiedades con los eventos del control
seleccionado


Asociar varios eventos a un mismo procedimiento
Cuando utilizamos 7andles para asociar eventos, podemos indicar que un mismo
procedimiento sirva para interceptar varios eventos. Veamos un caso prctico en el
que tenemos varios controles de tipo Te&tBo& y queremos que cuando reciban el
foco siempre se ejecute el mismo cdigo, por ejemplo, que se seleccione todo el
texto que contiene, podemos hacerlo indicando despus de la clusula 7andles
todos los controles que queremos asociar con ese procedimiento.
En el siguiente cdigo indicamos tres controles Te&tBo&:
?ri5ate S!b 1eGt,oG1+nter( +
,-$al sen%er As S-stem/0b#ect, +
,-$al e As S-stem/5entArgs) +
Han%les 1eGt,oG1/nter, 1eGt,oG2/nter,
1eGt,oG3/nter
n% S!b
Esta asociacin la podemos hacer manualmente, simplemente indicando en la
clusula 7andles cada uno de los eventos a continuacin del anterior separndolos
por comas. O bien desde el diseador de formularios. En este segundo caso, cuando
seleccionamos un control y desde la ventana de propiedades, seleccionamos un
104
evento, nos muestra los procedimientos que tenemos definidos en nuestro cdigo
que utilizan los mismos parmetros que el evento en cuestin, si seleccionamos uno
de esos procedimientos, el propio IDE aadir ese control a la lista 7andles.
Como vemos en la figura 1.04.04 podemos usar el procedimiento Te;tBo;$MEnter
para asociarlo al evento %nter del control Te;tBo;2:
Fi'ura $.0=.0= *ista de procedimientos Acompati#lesA con un evento

"eclarar una variable para asociar eventos con =andles
Para que podamos usar la instruccin 7andles para asociar manualmente un
procedimiento con un evento, o para que el diseador de Visual Basic 2005 pueda
hacerlo, la variable del control o clase que tiene los eventos que queremos
interceptar tenemos que declararla con la instruccin 4it"%ents.
Esto es exactamente lo mismo que en Visual Basic 6.0, lo que ocurre es que cuando
trabajamos con formularios desde VB6, no nos tenemos que preocupar de este
detalle, en Visual Basic 2005 tampoco debemos preocuparnos, ya que el propio
diseador de formularios lo hace por nosotros.
Aunque a diferencia de VB6, hay que hacerlo de forma explcita, ya que en la
versin anterior de Visual Basic no tenamos ningn control a como se definan o
declaraban los controles a usar en nuestro formulario, mientras que en esta nueva
versin siempre tendremos acceso a esa informacin. No vamos a entrar en ms
detalles, simplemente mostraremos cmo se declara el control Button1 para que
exponga los eventos:
)rien% <ith5ents ,!tton1 As S-stem/<in%oJs/)orms/,!tton
Si en lugar de estar trabajando con formularios y controles, lo hacemos con clases
"normales", la forma de declarar una variable que tiene eventos es por medio de la
instruccin 4it"%ents. Por ejemplo, en esta declaracin indicamos que tenemos
intencin de usar los eventos que la clase Empleado exponga:
105
?ri5ate <ith5ents !nm2lea%o As m2lea%o
Y posteriormente podremos definir los mtodos de eventos usando la instruccin
7andles:
?ri5ate S!b !nm2lea%o+DatosCambia%os() Han%les
!nm2lea%o/DatosCambia%os
n% S!b

Nota3
Usar WithEvents y Handles es la forma ms sencilla de declarar y usar
una variable que accede a una clase que produce eventos, pero no es
la nica forma que tenemos de hacerlo en Visual Basic 2005, tal como
tendremos oportunidad de comprobar.

/efinir % producir eventos en una clase
Como comentbamos anteriormente, la forma de definir un evento en una clase de
Visual Basic 2005 es idntica a como lo hacemos actualmente con VB6, lo mismo
ocurre cuando queremos "lanzar" o producir el evento: en Visual Basic 2005 se hace
igual que en Visual Basic 6.0.

"efinir eventos en una clase
Para definir un evento en una clase usamos la instruccin %ent seguida del nombre
del evento y opcionalmente indicamos los argumentos que dicho evento recibir.
En el siguiente trozo de cdigo definimos un evento llamado /atosModificados
que no utiliza ningn argumento:
?!blic 5ent DatosHo%i8ica%os()
Esto es todo lo que necesitamos hacer en Visual Basic 2005 para definir un evento,
que, como podemos comprobar, es exactamente igual que en VB6.

106
,roducir un evento en nuestra clase
Para producir un evento en nuestra clase, y de esta forma notificar a quin quiera
interceptarlo, simplemente usaremos la instruccin 'aise%ent seguida del evento
que queremos producir. Esto tampoco ha cambiado en Visual Basic 2005 con
respecto a VB6. Incluso cuando escribimos esa instruccin en el IDE, nos mostrar
los distintos eventos que podemos producir, tal como vemos en la figura 1.04.05:
Fi'ura $.0=.05 *ista de eventos &ue podemos producir

Esta es la forma ms sencilla de definir y lanzar eventos en Visual Basic 2005, que
como podemos comprobar es exactamente igual que en Visual Basic 6.0.

$tra forma de asociar los eventos de una clase con un m0todo
Tal como hemos estado comentando, la forma ms sencilla de declarar una variable
para interceptar eventos es declarndola usando 4it"%ents y para interceptar los
eventos lo hacemos por medio de la instruccin 7andles.
Esta forma, es a todas luces la ms recomendada, no solo por la facilidad de
hacerlo, sino porque tambin tenemos la ventaja de que todas las variables
declaradas con 4it"%ents se muestran en la lista desplegable de la ventan de
cdigo, tal como podemos apreciar en la figura 1.04.06:
Fi'ura $.0=.0" *ista de o#(etos &ue producen eventos
Y de esta forma podemos seleccionar la variable y posteriormente elegir el evento a
interceptar, tal como vimos en la figura 1.04.02.

107
Asociar eventos mediante Add0andler
Pero Visual Basic 2005 tambin proporciona otra forma de asociar un procedimiento
con un evento. Aunque en este caso es algo ms manual que todo lo que hemos
visto y, de alguna forma est ms ligado con los delegados, y como los delegados
los veremos dentro de poco, ahora solamente mostraremos la forma de hacerlo y
despus veremos con algo de ms detalle cmo funciona.
La forma de de asociar eventos con su correspondiente mtodo es por medio de la
instruccin *dd7andler. A esta instruccin le pasamos dos argumentos, el primero
es el evento a asociar y el segundo es el procedimiento que usaremos cuando se
produzca dicho evento. Este ltimo parmetro tendremos que indicarlo mediante la
instruccin *ddressOf, que al igual que en VB6 sirve para pasar una referencia a
una funcin o procedimiento, y precisamente eso es lo que queremos hacer:
indicarle que procedimiento debe usar cuando se produzca el evento:
A%%Han%ler !nm2lea%o/DatosCambia%os, A%%ress08
!nm2lea%o+DatosCambia%os
En este caso, el uso de *ddressOf es una forma "fcil" que tiene Visual Basic 2005
de asociar un procedimiento de evento con el evento. Aunque por el fondo, (y sin
que nos enteremos), realmente lo que estamos usando es un constructor a un
delegado.
La ventaja de usar esta forma de asociar eventos con el procedimiento, es que
podemos hacerlo con variables que no estn declaradas con 4it"%ents, realmente
esta sera la nica forma de asociar un procedimiento de evento con una variable
que no hemos declarado con 4it"%ents.

Desasociar eventos mediante 3emove0andler
De la misma forma que por medio de *dd7andler podemos asociar un
procedimiento con un evento, usando la instruccin 'emoe7andler podemos hacer
el proceso contrario: desligar un procedimiento del evento al que previamente
estaba asociado.
Los parmetros a usar con 'emoe7andler son los mismos que con *dd7andler.
Podemos usar 'emoe7andler tanto con variables y eventos definidos con
*dd7andler como con variables declaradas con 4it"%ents y ligadas por medio de
7andles.
Esto ltimo es as porque cuando nosotros definimos los procedimientos de eventos
usando la instruccin 7andles, es el propio Visual Basic el que internamente utiliza
*dd7andler para ligar ese procedimiento con el evento en cuestin. Saber esto nos
facilitar comprender mejor cmo funciona la declaracin de eventos mediante la
instruccin Custom, aunque de este detalle nos ocuparemos despus de ver que son
los delegados.

108
/ele'ados
Como hemos comentado anteriormente, los eventos son acciones que una clase
puede producir cuando ocurre algo. De esta forma podemos notificar a las
aplicaciones que hayan decidido interceptar esos mensajes para que tomen las
acciones que crean conveniente.
Visual Basic 2005 esconde al desarrollador prcticamente todo lo que ocurre cada
vez que decidimos interceptar un evento, nosotros solo vemos una pequea parte
de todo el trabajo que en realidad se produce, y el que no lo veamos no quiere decir
que no est ocurriendo nada. Tambin es cierto que no debe preocuparnos
demasiado si no sabemos lo que est pasando, pero si tenemos conciencia de que
es lo que ocurre, puede que nos ayude a comprender mejor todo lo relacionado con
los eventos.

78u0 ocurre cuando se asigna y se produce un evento9
Intentemos ver de forma sencilla lo que ocurre "por dentro" cada vez que definimos
un mtodo que intercepta un evento y cmo hace el Visual Basic para comunicarse
con el receptor de dicho evento.
1. Cuando Visual Basic se encuentra con el cdigo que le indica que un mtodo
debe interceptar un evento, ya sea mediante *dd7andler o mediante el uso
de 7andles, lo que hace es aadir la direccin de memoria de ese mtodo a
una especie de array.
En la figura 1.04.07 podemos ver un diagrama en el que un mismo evento lo
interceptan tres clientes, cuando decimos que un cliente intercepta un evento,
realmente nos referimos a que hay un mtodo que lo intercepta y el evento
realmente guarda la direccin de memoria de ese mtodo.
109
Fi'ura $.0=.0D El evento 'uarda la direccin de memoria de cada mHtodo
&ue lo intercepta
2. Cuando usamos la instruccin 'aise%ent para producir el evento, se examina
esa lista de direcciones y se manda el mensaje a cada uno de los mtodos
que tenemos en el "array".
En este caso, lo que realmente ocurre es que se hace una llamada a cada uno
de los mtodos, de forma que se ejecute el cdigo al que tenemos acceso
mediante la direccin de memoria almacenada en la lista.
3. Cuando usamos la instruccin 'emoe7andler, le estamos indicando al evento
que elimine de la lista el mtodo indicado en esa instruccin, de esta forma,
la prxima vez que se produzca el evento, solo se llamar a los mtodos que
actualmente estn en la lista.
Tanto el agregar nuevos mtodos a esa lista como quitarlos, lo podemos hacer en
tiempo de ejecucin, por medio de *dd7andler y 'emoe7andler respectivamente.
Ya que la instruccin 7andles solo la podemos usar en tiempo de diseo.
Es ms, podemos incluso indicar que un mismo evento procese ms de un mtodo
en una misma aplicacin o que un mismo mtodo sea llamado por ms de un
evento. Ya que lo que realmente necesita cada evento es que exista un mtodo que
tenga una "firma" concreta: la indicada al declarar el evento.

78u0 papel uegan los delegados en todo este proceso9
Veamos primero que papel tienen los delegados en todo este proceso y despus
veremos con ms detalle lo que "realmente" es un delegado.
1. Cuando definimos un evento, realmente estamos definiendo un delegado,
(que en el fondo es una clase con un tratamiento especial), y un mtodo del
mismo tipo que el delegado
2. Cuando indicamos que un mtodo intercepte un evento, realmente estamos
llamando al constructor del delegado, al que le pasamos la direccin de
memoria del mtodo. El delegado almacena cada una de esas direcciones de
memoria para posteriormente usarlas
3. Cuando se produce el evento, (por medio de 'aise%ent), realmente estamos
llamando al delegado para que acceda a todas las "direcciones" de memoria
que tiene almacenadas y ejecute el cdigo que hayamos definido en cada uno
de esos mtodos
Como podemos comprobar, y para decirlo de forma simple, un delegado realmente
es la forma que tiene .NET para definir un puntero. La diferencia principal es que los
punteros, (no vamos a entrar en demasiados detalles sobre los punteros, ya que no
estamos en un curso de C/C++), no tienen forma de comprobar si estn accediendo
a una direccin de memoria correcta o, para decirlo de otra forma, a una direccin
de memoria "adecuada". En .NET, los "punteros" solo se pueden usar mediante
delegados, y stos solamente pueden acceder a direcciones de memoria que tienen
la misma "firma" con el que se han definido. Para que lo entendamos un poco
mejor, es como si los delegados solo pudieran acceder a sitios en la memoria que
110
contienen un mtodo con la misma "interfaz" que el que ha definido el propio
delegado.
Seguramente es difcil de entender, y la principal razn es que hemos empezado la
casa por el techo.
Por tanto, veamos a continuacin una definicin "formal" de qu es un delegado y
veamos varios ejemplos para que lo comprendamos mejor.

"efinici(n >formal> de delegado
Veamos que nos dice la documentacin de Visual Basic 2005 sobre los delegados:
8,n delegado es una clase 9ue puede contener una referencia a un m:todo. *
diferencia de otras clases3 los delegados tienen un prototipo /firma0 y pueden
guardar referencias ;nicamente a los m:todos 9ue coinciden con su
prototipo.8
Esta definicin, al menos en lo que respecta a su relacin con los eventos, viene a
decir que los delegados definen la forma en que debemos declarar los mtodos que
queramos usar para interceptar un evento.
Por ejemplo, el evento /atos-am#iados definido anteriormente, tambin lo
podramos definir de la siguiente forma:
?!blic Delegate S!b DatosCambia%os5entHan%ler()
?!blic 5ent DatosCambia%os As DatosCambia%os5entHan%ler
Es decir, el mtodo que intercepte este evento debe ser del tipo Sub y no recibir
ningn parmetro.
Si nuestro evento utiliza, por ejemplo, un parmetro de tipo String, la definicin del
delegado quedara de la siguiente forma:
?!blic Delegate S!b AombreCambia%o5entHan%ler(,-$al n!e5oAombre
As String)
Y la definicin del evento quedara de esta otra:
?!blic 5ent AombreCambia%o As AombreCambia%o5entHan%ler
Como vemos al definir el evento ya no tenemos que indicar si recibe o no algn
parmetro, ya que esa definicin la hemos hecho en el delegado.
111
Si nos decidimos a definir este evento de la forma "normal" de Visual Basic, lo
haramos as:
?!blic 5ent AombreCambia%o(,-$al n!e5oAombre As String)
Como podemos comprobar, Visual Basic 2005 nos permite definir los eventos de dos
formas distintas: definiendo un delegado y un evento que sea del tipo de ese
delegado o definiendo el evento con los argumentos que debemos usar.
Declaremos como declaremos los eventos, los podemos seguir usando de la misma
forma, tanto para producirlo mediante 'aise%ent como para definir el mtodo que
reciba ese evento.

:tili*ar un delegado para acceder a un m0todo
Ahora veamos brevemente cmo usar los delegados, en este caso sin necesidad de
que defina un evento.
Como hemos comentado, un delegado realmente es una clase que puede contener
una referencia a un mtodo, adems define el prototipo del mtodo que podemos
usar como referencia. Sabiendo esto, podemos declarar una variable del tipo del
delegado y por medio de esa variable acceder al mtodo que indiquemos, siempre
que ese mtodo tenga la misma "firma" que el delegado. Parece complicado
verdad? Y no solo lo parece, es que realmente lo es. Comprobemos esta
"complicacin" por medio de un ejemplo. En este cdigo, que iremos mostrando
poco a poco, vamos a definir un delegado, un mtodo con la misma firma para que
podamos usarlo desde una variable definida con el mismo tipo del delegado.
Definimos un delegado de tipo Sub que recibe un valor de tipo cadena:
Delegate S!b Sal!%o(,-$al nombre As String)
Definimos un mtodo con la misma firma del delegado:
?ri5ate S!b mostrarSal!%o(,-$al elAombre As String)
Console/<rite'ine("Hola, " P elAombre)
n% S!b
Ahora vamos a declarar una variable para que acceda a ese mtodo.
Para ello debemos declararla con el mismo tipo del delegado:
Dim sal!%an%o As Sal!%o
La variable saludando es del mismo tipo que el delegado Saludo. La cuestin es
cmo o que asignamos a esta variable?
112
Primer intento:
Como hemos comentado, los delegados realmente son clases, por tanto podemos
usar Ne Saludo y, segn parece, deberamos pasarle un nombre como
argumento. Algo as:
sal!%an%o = AeJ Sal!%o("?e2e")
Pero esto no funciona, entre otras cosas, porque hemos comentado que un
delegado contiene (o puede contener) una referencia a un mtodo, y A8epeA no es
un mtodo ni una referencia a un mtodo.
Segundo intento:
Por lgica y, sobre todo, por sentido comn, mxime cuando hemos declarado un
mtodo con la misma "firma" que el delegado, deberamos pensar que lo que
debemos pasar a esa variable es el mtodo, ya que un delegado puede contener
una referencia a un mtodo.
sal!%an%o = AeJ Sal!%o(mostrarSal!%o)
Esto tampoco funciona, seguramente porque le falta el parmetro?
sal!%an%o = AeJ Sal!%o(mostrarSal!%o("?e2e"))
Pues tampoco.
Para usar un delegado debemos indicarle la direccin de memoria de un mtodo, a
eso se refiere la definicin que vimos antes, una referencia a un mtodo no es ni
ms ni menos que la direccin de memoria de ese mtodo. Y en Visual Basic, desde
la versin 5.0, tenemos una instruccin para obtener la direccin de memoria de
cualquier mtodo: *ddressOf.
Por tanto, para indicarle al delegado dnde est ese mtodo tendremos que usar
cualquiera de estas dos formas:
sal!%an%o = AeJ Sal!%o(A%%ress08 mostrarSal!%o)
Es decir, le pasamos al constructor la direccin de memoria del mtodo que
queremos "asociar" al delegado.
En Visual Basic esa misma asignacin la podemos simplificar de esta forma:
sal!%an%o = A%%ress08 mostrarSal!%o
Ya que el compilador "sabe" que saludando es una variable de tipo delegado y lo
que esa variable puede contener es una referencia a un mtodo que tenga la misma
firma que la definicin del delegado, en nuestro caso, que sea de tipo Sub y reciba
una cadena.
113
Si queremos, tambin podemos declarar la variable y asignarle directamente el
mtodo al que har referencia:
Dim sal!%an%o As AeJ Sal!%o(A%%ress08 mostrarSal!%o)
Y ahora... cmo podemos usar esa variable?
La variable saludando realmente est apuntando a un mtodo y ese mtodo recibe
un valor de tipo cadena, por tanto si queremos llamar a ese mtodo (para que se
ejecute el cdigo que contiene), tendremos que indicarle el valor del argumento,
sabiendo esto, la llamada podra ser de esta forma:
sal!%an%o("?e2e")
Y efectivamente, as se mostrara por la consola el saludo (Hola) y el valor indicado
como argumento.
Realmente lo que hacemos con esa llamada es acceder al mtodo al que apunta la
variable y como ese mtodo recibe un argumento, debemos pasrselo, en cuanto lo
hacemos, el runtime de .NET se encarga de localizar el mtodo y pasarle el
argumento, de forma que se ejecute de la misma forma que si lo llamsemos
directamente:
mostrarSal!%o("?e2e")
Con la diferencia de que la variable "saludando" no tiene porqu saber a qu
mtodo est llamando, y lo ms importante, no sabe dnde est definido ese
mtodo, solo sabe que el mtodo recibe un parmetro de tipo cadena y aparte de
esa informacin, no tiene porqu saber nada ms.

As es como funcionan los eventos, un evento solo tiene la direccin de memoria de
un mtodo, ese mtodo recibe los mismos parmetros que los definidos por el
evento (realmente por el delegado), cuando producimos el evento con 'aise%ent
es como si llamramos a cada uno de los mtodos que se han ido agregando al
delegado, si es que se ha agregado alguno, ya que en caso de que no haya ningn
mtodo asociado a ese evento, ste no se producir, por la sencilla razn de que no
habr ningn cdigo al que llamar.

Realmente es complicado y, salvo que lo necesitemos para casos especiales, no ser
muy habitual que usemos los delegados de esta forma, aunque no est de ms
saberlo, sobre todo si de as comprendemos mejor cmo funcionan los eventos.

114
/efinir un evento #ien informado
Para terminar con esta leccin sobre los eventos y los delegados, vamos a ver otra
forma de definir un evento. Esta es exclusiva de Visual Basic 2005 y por medio de
esta declaracin, tal como indicamos en el ttulo de la seccin, tendremos mayor
informacin sobre cmo se declara el evento, cmo se destruye e incluso cmo se
produce, es lo que la documentacin de Visual Basic llama evento personalizado
(Custom %ent).
Cuando declaramos un evento usando la instruccin Custom estamos definiendo
tres bloques de cdigo que nos permite interceptar el momento en que se produce
cualquiera de las tres acciones posibles con un evento:
1. Cuando se "liga" el evento con un mtodo, ya sea por medio de *dd7andler o
mediante 7andles
2. Cuando se desliga el evento de un mtodo, por medio de 'emoe7andler
3. Cuando se produce el evento, al llamar a 'aise%ent
Para declarar este tipo de evento, siempre debemos hacerlo por medio de un
delegado.
Veamos un ejemplo de una declaracin de un evento usando Custom %ent:
?!blic Delegate S!b A2elli%osCambia%os5entHan%ler(,-$al n!e5o As
String)
?!blic C!stom 5ent A2elli%osCambia%os As
A2elli%osCambia%os5entHan%ler
A%%Han%ler(,-$al 5al!e As A2elli%osCambia%os5entHan%ler)
4 este bloI!e se e#ec!tar6 ca%a 5e& I!e asignemos !n
mRto%o al e5ento
n% A%%Han%ler

"emo5eHan%ler(,-$al 5al!e As A2elli%osCambia%os5entHan%ler)
4 este bloI!e se e#ec!tar6 c!an%o se %eslig!e el e5ento %e
!n mRto%o
n% "emo5eHan%ler

"aise5ent(,-$al n!e5o As String)
4 este bloI!e se e#ec!tar6 ca%a 5e& I!e se 2ro%!&ca el
e5ento
115
n% "aise5ent
n% 5ent
Como podemos apreciar, debemos definir un delegado con la "firma" del mtodo a
usar con el evento.
Despus definimos el evento por medio de las instrucciones Custom %ent,
utilizando el mismo formato que al definir un evento con un delegado.
Dentro de la definicin tenemos tres bloques, cada uno de los cuales realizar la
accin que ya hemos indicado en la lista numerada.

Nota3
Los eventos Custom Event solamente podemos definirlos e
interceptarlos en el mismo ensamblado.

Introduccin
Esta es la definicin que nos da la ayuda de Visual Basic sobre lo que es un atributo.
Los atributos son eti9uetas descriptias 9ue proporcionan informaci<n
adicional sobre elementos de programaci<n como tipos3 campos3 m:todos y
propiedades. Otras aplicaciones3 como el compilador de #isual Basic3 pueden
"acer referencia a la informaci<n adicional en atributos para determinar c<mo
pueden utili.arse estos elementos.
En esta leccin veremos algunos ejemplos de cmo usarlos en nuestras propias
aplicaciones y, aunque sea de forma general, cmo usar y aplicar algunos de los
atributos definidos en el propio .NET Framework, al menos los que ms
directamente nos pueden interesar a los desarrolladores de Visual Basic.

4tri#utos
Atributos
o Atributos para representar informacin de nuestra aplicacin
Mostrar los ficheros ocultos del proyecto
o Tipos de atributos que podemos usar en una aplicacin
Atributos globales a la aplicacin
Atributos particulares a las clases o miembros de las clases
o Atributos personalizados
Acceder a los atributos personalizados en tiempo de ejecucin
o Atributos especficos de Visual Basic
o Marcar ciertos miembros de una clase como obsoletos
116

4tri#utos
Como hemos comentado en la introduccin, los atributos son etiquetas que
podemos aplicar a nuestro cdigo para que el compilador y, por extensin, el
propio .NET Framework los pueda usar para realizar ciertas tareas o para obtener
informacin extra sobre nuestro cdigo.
De hecho en cualquier aplicacin que creemos con Visual Basic 2005 estaremos
tratando con atributos, aunque nosotros ni nos enteremos, ya que el propio
compilador los utiliza para generar los metadatos del ensamblado, es decir, la
informacin sobre todo lo que contiene el ejecutable o librera que hemos creado
con Visual Basic 2005.
Por otra parte, el uso de los atributos nos sirve para ofrecer cierta funcionalidad
extra a nuestro cdigo, por ejemplo, cuando creamos nuestros propios controles,
mediante atributos podemos indicarle al diseador de formularios si debe mostrar
ciertos miembros del control en la ventana de propiedades, etc.

Atributos para representar informaci(n de nuestra aplicaci(n
De forma ms genrica podemos usar los atributos para indicar ciertas
caractersticas de nuestra aplicacin, por ejemplo, el ttulo, la versin, etc. Todos
estos atributos los indicaremos como "caractersticas" de nuestra aplicacin, y lo
haremos sin ser demasiados conscientes de que realmente estamos usando
atributos, ya que el propio Visual Basic los controla mediante propiedades de la
aplicacin.
Por ejemplo, si mostramos la ventana de propiedades de nuestro proyecto, ver
figura 1.05.01:
117
Fi'ura $.05.0$ 8ropiedades de la aplicacin
Tendremos acceso a las propiedades de la aplicacin, como el nombre del
ensamblado, el espacio de nombres, etc. Si queremos agregar informacin extra,
como la versin, el copyright, etc. podemos pulsar en el botn "Assembly
Information", al hacerlo, se mostrar una nueva ventana en la que podemos escribir
esa informacin, tal como mostramos en la figura 1.05.02:
118
Fi'ura $.05.02 Informacin del ensam#lado
Esa informacin realmente est definida en un fichero del proyecto llamado
AssembluInfo.vb, el cual de forma predeterminada est oculto, si lo mostramos,
veremos que esa informacin la contiene en formato de atributos.
Parte del cdigo de ese fichero lo podemos ver en la figura 1.05.03:
119
Fi'ura $.05.0< -ontenido del fic?ero 4ssem#l%Info
En este cdigo podemos resaltar tres cosas:
La primera es que tenemos una importacin al espacio de nombres
S%stem.Beflection, este espacio de nombres contiene la definicin de las
clases/atributos utilizados para indicar los atributos de la aplicacin, como el ttulo,
etc.
La segunda es la forma de usar los atributos, estos deben ir encerrados entre signos
de menor y mayor: >4ssem#l%3 -omVisi#le9False:6.
La tercera es que, en este caso, los atributos estn definidos a nivel de ensamblado,
para ellos se aade la instruccin 4ssem#l%3 al atributo.
Como veremos a continuacin, los atributos tambin pueden definirse a nivel local,
es decir, solo aplicable al elemento en el que se utiliza, por ejemplo, una clase o un
mtodo, etc.

120
Mostrar los fic%eros ocultos del proyecto
Como acabamos de comentar, el fichero AssemblyInfo.vb que es el que contiene la
informacin sobre la aplicacin (o ensamblado), est oculto. Para mostrar los
ficheros ocultos, debemos hacer lo siguiente:
En la ventana del explorador de soluciones, pulsamos en el segundo botn, (si
pasamos el cursor por encima, mostrar un mensaje que indica "Mostrar todos los
ficheros"), de esta forma tendremos a la vista todos los ficheros de la aplicacin,
incluso el de los directorios en el que se crea el ejecutable, tal como podemos
apreciar en la figura 1.05.04:
Fi'ura $.05.0= Mostrar todos los fic?eros de la solucin

Tipos de atributos 6ue podemos usar en una aplicaci(n
Como hemos comentado, existen atributos que son globales a toda la aplicacin y
otros que podremos aplicar a elementos particulares, como una clase o un mtodo.
Atributos "lobales a la aplicacin
Estos se indican usando *ssembly= en el atributo y los podremos usar en cualquier
parte de nuestro cdigo, aunque lo habitual es usarlos en el fichero
AssemblyInfo.vb.

Nota3
La palabra o instruccin Assembly: lo que indica es que el atributo
tiene un mbito de ensamblado.
121

Atributos particulares a las clases o miembros de las clases
Estos atributos solo se aplican a la clase o al miembro de la clase que creamos
conveniente, el formato es parecido a los atributos globales, ya que se utilizan los
signos de menor y mayor para encerrarlo, con la diferencia de que en este tipo de
atributos no debemos usar *ssembly=, ya que esta instruccin indica que el atributo
es a nivel del ensamblado.
Cuando aplicamos un atributo "particular", este debe estar en la misma lnea del
elemento al que se aplica, aunque si queremos darle mayor legibilidad al cdigo
podemos usar un guin bajo para que el cdigo contine en otra lnea:
(Hicroso8t/$is!al,asic/Hi%eHo%!leAame()* +
Ho%!le H-"eso!rces

Atributos personali*ados
Adems de los atributos que ya estn predefinidos en el propio .NET o Visual Basic,
podemos crear nuestros propios atributos, de forma que en tiempo de ejecucin
podamos acceder a ellos mediante las clases del espacio de nombres 'eflection,
aunque debido a que este tema se sale un poco de la intencin de este curso,
simplemente indicar que los atributos personalizados son clases que se derivan de
la clase System.*ttribute y que podemos definir las propiedades que creamos
conveniente utilizar en ese atributo para indicar cierta informacin a la que
podemos acceder en tiempo de ejecucin.
En el siguiente cdigo tenemos la declaracin de una clase que se utilizar como
atributo personalizado, notamos que, por definicin las clases para usarlas como
atributos deben acabar con la palabra *ttribute despus del nombre "real" de la
clase, que como veremos en el cdigo que utiliza ese atributo, esa "extensin" al
nombre de la clase no se utiliza.
Veamos primero el cdigo del atributo personalizado:
(Attrib!teFsage(Attrib!te1argets/All)* +
?!blic Class A!torAttrib!te
Inherits S-stem/Attrib!te
4
?ri5ate +Ho%i8ica%o?or As String
?ri5ate +$ersion As String
122
?ri5ate +)echa As String
4
?!blic ?ro2ert- Ho%i8ica%o?or() As String
;et
"et!rn +Ho%i8ica%o?or
n% ;et
Set(,-$al 5al!e As String)
+Ho%i8ica%o?or = 5al!e
n% Set
n% ?ro2ert-
4
?!blic ?ro2ert- $ersion() As String
;et
"et!rn +$ersion
n% ;et
Set(,-$al 5al!e As String)
+$ersion = 5al!e
n% Set
n% ?ro2ert-
4
?!blic ?ro2ert- )echa() As String
;et
"et!rn +)echa
n% ;et
Set(,-$al 5al!e As String)
+)echa = 5al!e
n% Set
n% ?ro2ert-
n% Class
123
Para usar este atributo lo podemos hacer de la siguiente forma:
(A!tor(Ho%i8ica%o?orD=";!illermo 4g!ille4", +
$ersionD="1/0/0/0", )echaD="13VAbrV2005")* +
?!blic Class ?r!ebaAtrib!tos

Nota3
Cuando utilizamos el atributo, en el constructor que de forma
predeterminada crea Visual Basic, los parmetros se indican por el
orden alfabtico de las propiedades, pero que nosotros podemos
alterar usando directamente los nombres de las propiedades, tal como
podemos ver en el cdigo de ejemplo anterior.


Acceder a los atributos personali4ados en tiempo de ejecucin
Para acceder a los atributos personalizados podemos hacer algo como esto,
(suponiendo que tenemos la clase 4utor4ttri#ute y una clase llamada
8rue#a4tri#utos a la que hemos aplicado ese atributo personalizado):
S!b Hain()
Dim ti2o As 1-2e
ti2o = ;et1-2e(?r!ebaAtrib!tos)
Dim atrib!tos() As Attrib!te
atrib!tos = Attrib!te/;etC!stomAttrib!tes(ti2o)
)or ach atr As Attrib!te In atrib!tos
I8 1-2e08 atr Is A!torAttrib!te 1hen
Dim a!t As A!torAttrib!te
a!t = C1-2e(atr, A!torAttrib!te)
Console/<rite'ine("Ho%i8ica%o 2orD " P
a!t/Ho%i8ica%o?or)
124
Console/<rite'ine(")echaD " P a!t/)echa)
Console/<rite'ine("$ersiSnD " P a!t/$ersion)
n% I8
AeGt
n% S!b


Atributos espec!ficos de Visual .asic
Visual Basic utiliza una serie de atributos para indicar ciertas caractersticas de
nuestro cdigo, en particular son tres:
-7M-lass4ttri#ute
o Este atributo se utiliza para simplificar la creacin de componentes
COM desde Visual Basic.
VBFi;edStrin'4ttri#ute
o Este atributo se utiliza para crear cadenas de longitud fija en Visual
Basic 2005. Habitualmente se aplica a campos o miembros de una
estructura, principalmente cuando queremos acceder al API de
Windows o cuando queremos usar esa estructura para guardar
informacin en un fichero, pero utilizando una cantidad fija de
caracteres.
VBFi;ed4rra%4ttri#ute
o Este atributo, al igual que el anterior, lo podremos usar para declarar
arrays de tamao fijo, al menos si las declaramos en una estructura,
ya que por defecto, los arrays de Visual Basic son de tamao variable.

%arcar ciertos miembros de una clase como obsoletos
En ocasiones nos encontraremos que escribimos cierto cdigo que posteriormente
no queremos que se utilice, por ejemplo porque hemos creado una versin
optimizada.
Si ese cdigo lo hemos declarado en una interfaz, no deberamos eliminarlo de ella,
ya que as romperamos el contrato contrado por las clases que implementan esa
interfaz. En estos casos nos puede venir muy bien el uso del atributo >Obsolete?,
ya que as podemos informar al usuario de que ese atributo no debera usarlo. En el
constructor de este atributo podemos indicar la cadena que se mostrar al usuario.
En el siguiente cdigo se declara un mtodo con el atributo Obsolete:
?!blic Inter8ace I?r!eba0bsoleto
125
(0bsolete("ste mRto%o -a est6 obsoleto, !tili&a el mRto%o
Hostrar")* +
S!b HostrarAombre()
S!b Hostrar()
n% Inter8ace
Si trabajamos con el IDE de Visual Basic, ese mensaje se mostrar al compilar o
utilizar los atributos marcados como obsoletos, tal como podemos apreciar en la
figura 1.05.05:
Fi'ura $.05.05 Mensa(e de &ue un mHtodo est. o#soleto
/ES4BB7**7
%(dulo 1 ? -ntroducci(n
En este mdulo, conoceremos las partes generales y ms importantes del entorno de
desarrollo rpido Visual Basic 2005 Express para la programacin de aplicaciones
Visual Basic 2005.
Veremos no slo los principales controles del entorno, sino tambin, los cambios ms
destacables respecto a Visual Basic 6.
Adems, veremos como desarrollar nuestros propios controles Windows,
aprenderemos a trabajar con imgenes y grficos con Visual Basic .NET y finalmente,
conoceremos como desplegar nuestras aplicaciones desarrolladas en Visual Basic
2005.
F4N3
Qu tipo de aplicaciones puedo desarrollar con Visual Basic 2005
Express?
+odr@ desarrollar principalmente3 Aplicaciones para Windows3
i!liotecas de "lases y Aplicaciones de "onsola. *dem@s3 podr@
aAadir sus propias plantillas para obtener un mayor rendimiento en el
desarrollo de aplicaciones.
Si su inter:s es el desarrollo de aplicaciones 4eb3 puede utili.ar
#isual We! De$eloper 2005 %&press.
Productos Visual Studio Express
126
Las partes que forman parte de este mdulo son las siguientes:
Cap!tulo @

Uso del diseador de Visual Basic 2005 Express
Cap!tulo 1

Controles de Windows Forms
Cap!tulo A

Desarrollo de controles
Cap!tulo B

Trabajo con imgenes y grficos
Cap!tulo 3

Despliegue de aplicaciones

-ntroducci(n
Cuando nos encontramos con Visual Basic 2005 Express por primera vez, saltan a la
vista, algunos de los cambios ms importantes entre Visual Basic 6 y este novedoso
entorno de desarrollo de aplicaciones Windows.
En primer lugar, tenemos que saber que Visual Basic 2005 Express es un entorno
monoprogramacin, es decir, es un entorno con el que podremos desarrollar
aplicaciones Windows con Visual Basic 2005. Adems, tambin podremos reutilizar
controles y libreras escritas en otros lenguajes de la plataforma .NET.
Para un desarrollador, familiarizarse con el entorno de Visual Basic 2005 Express es
una tarea que no debe entraar una complejidad excesivamente grande. Como nos
ocurre a todos los que nos encontramos delante de un nuevo entorno de trabajo, lo
nico que se requiere es constancia y prctica, mucha prctica. Sin embargo, si usted
es ya un desarrollador habitual de Visual Basic 6, notar que sus avances van a ser
significativos en muy poco tiempo.
De todos los modos, con el fin de facilitar su comprensin con el nuevo entorno,
veremos tambin aquellas diferencias y similitudes ms destacables para el
programador entre los entornos de Visual Basic 2005 Express y el de Visual Basic 6,
para que el desarrollador que se encuentre por primera vez con este entorno, se
familiarice lo antes posible con l.
%(dulo 1 ? Cap!tulo @

1. Cuadro de herramientas
2. Explorador de base de datos
127
3. Explorador de soluciones
4. Propiedades
5. Menus y barra de botones
6. Otras consideraciones
%(dulo 1 ? Cap!tulo @
@. Cuadro de #erramientas
El cuadro o barra de herramientas de Visual Basic 2005 Express, vara ligeramente con
respecto al cuadro de herramientas de Visual Basic 6. Como en Visual Basic 6, esta
barra aparece por defecto en el margen izquierdo. A diferencia de Visual Basic 6, en
Visual Basic 2005 Express tenemos una gran cantidad de controles dispuestos en
diferentes categoras.
Una diferencia visual de las barras de herramientas entre Visual Basic 6 y Visual Basic
2005 Express, es la que se aprecia en figura 1.
&isual #asic )*+ &isual #asic ,++- 5press
Figura 1
El Cuadro de "erramientas, lo localizar en la parte izquierda del entorno #isual Basic
2BBC %&press.
Cuando iniciamos un nuevo proyecto con Visual Basic 2005 Express, el cuadro de
herramientas queda rellenado con los controles que podemos utilizar en el proyecto. Si
abrimos un formulario Windows, los controles quedan habilitados para que los
podamos insertar en el formulario Windows. En la figura 2 se muestra la barra de
herramientas con los controles preparados para ser insertados en el formulario
Windows.
128
$oolbo5 de &isual #asic ,++- 5press con controles 6indo7s preparados para ser insertados en el formulario 6indo7s
Figura 2
Nota3
Para insertar un control en un formulario Windows, se requiere que el
formulario Windows sobre el que deseamos insertar un control, est
abierto. Una vez que est abierto, bastar con realizar una de las tres
siguientes acciones para insertar un control al formulario:
D 7acer doble clic sobre un control del cuadro de "erramientas
D 7acer clic sobre un control del cuadro de "erramientas3 y sin soltar
el bot<n del rat<n3 arrastrarlo sobre el formulario
D 7acer clic sobre un control del cuadro de "erramientas3 y luego
"acer clic sobre el formulario y arrastrar para marcar una .ona 9ue
cubrir@ nuestro control y soltar el rat<n
El control quedar entonces insertado dentro del formulario.

129

%(dulo 1 ? Cap!tulo @
1. E;plorador de base de datos
Si ha sido lo suficientemente observador cuando se explicaban los detalles del cuadro
o barra de herramientas, y ha prestado especial atencin a las figuras o a las ventanas
del entorno de desarrollo de Visual Basic 2005 Express, quizs haya notado que en la
parte izquierda adems de la solapa cuadro de "erramientas, aparece otra solapa de
nombre e&plorador de base de datos.
Esta solapa es nueva para los desarrolladores de Visual Basic 6, y en ella, un
programador puede acceder a diferentes recursos del sistema. El principal y ms
importante recurso, es el que tiene que ver con las conexiones con bases de datos, ya
sean Microsoft Access, Microsoft SQL Server o cualquier otra fuente de datos.
En la figura 1 puede observar la solapa %&plorador de base de datos extendida con
parte de sus opciones.
La solapa del 5plorador de base de datos desple"ada de &isual #asic ,++- 5press
Figura 1
Conectando con una base de datos %icrosoft Access a trav0s de $'E ".
Para muestra un botn, y dado el carcter prctico de este tutorial, aprender a crear
una conexin con cualquier base de datos, en nuestro caso de ejemplo una base de
datos Microsoft Access, para poder utilizarla fcilmente en nuestra aplicacin Windows.
Haga clic sobre el botn representado por la siguiente imagen . En este instante,
se abrir una nueva ventana como la que se muestra en la figura 2.
130
&entana A"re"ar cone5in8 para establecer las propiedades de cone5in con una fuente de datos
Figura 2
Por defecto, la ventana A're'ar cone&i(n queda preparada para establecer una
conexin con una fuente de datos de origen de datos OL% DB, por lo que si nuestra
intencin es establecer una conexin con otra fuente de datos, entonces deberemos
hacer clic sobre el botn "a)!iar*** que se indica en la figura 3.
#otn Cambiar*** para seleccionar otro proveedor de ori"en de datos
Figura 3
De esta manera, podemos indicar el origen de acceso a datos que necesitamos para
establecer la conexin con nuestra fuente de datos, y que en nuestro ejemplo, no ser
un proveedor de SQL Server, por lo que el origen de datos OLE DB es vlido para
nosotros.
Una vez que hemos hecho clic sobre el botn "a)!iar***, nos aseguramos por lo
tanto, que nuestro origen de datos es base de datos de (icrosoft *ccess /OL% DB0,
como se indica en la figura 4.
131
&entana de seleccin del proveedor u ori"en de datos
Figura 4
F4N3
Puedo utilizar el proveedor OLE DB en lugar del proveedor de SQL
Server para conectar con una base de datos SQL Server?
Con OL% DB3 puede acceder a fuentes de datos SEL Serer u otras
fuentes de datos como (icrosoft *ccess3 sin embargo3 si utili.a SEL
Serer F.B3 SEL Serer 2BBB < SEL Serer 2BBC3 se recomienda el uso
del proeedor de SEL Serer3 9ue es un proeedor de acceso a datos
natio 9ue aumenta el rendimiento de nuestras aplicaciones con SEL
Serer. S<lo si utili.a una ersi<n de SEL Serer anterior a SEL Serer
F.B3 deber@ utili.ar necesariamente el proeedor de acceso a datos
OL% DB.
Una vez que hemos seleccionado el proveedor de acceso a datos, nos centraremos en
la opcin +o)!re de arc,i$o !ase de datos como se muestra en la figura 5.
132
n este lu"ar indicaremos el fic%ero de base de datos con el que estableceremos la cone5in
Figura 5
Para agregar el fichero de base de datos a la conexin, pulsaremos el botn
E;aminar... y seleccionaremos el fichero de base de datos de nuestro disco duro.
De esta manera, la base de datos quedar indicada en la conexin y tan slo
deberemos probar nuestra conexin pulsando el botn 8ro#ar cone;in como se
indica en la figura 6.
133
s recomendable probar la cone5in antes de a"re"arla al entorno
Figura 6
Si la prueba de conexin se ha realizado satisfactoriamente, recibiremos un mensaje
en pantalla afirmativo como el que se indica en la figura 7.
9rueba de la cone5in reali4ada con 5ito
Figura 7
4 tener en cuenta3
En este ejemplo, la conexin con la base de datos Microsoft Access, no
tiene ningn tipo de usuario y contrasea. Tenga en cuenta que en la
parte identificada como -one;in con la #ase de datos, podramos
indicar el usuario y contrasea si fuera necesario.
En este punto, tan slo deberemos pulsar sobre el botn 4ceptar para que la base de
datos con la que hemos establecido la conexin, quede ahora insertada en la ventana
del %&plorador de !ase de datos como se muestra en la figura 8.
#ase de datos Microsoft Access insertada en la ventana del 5plorador de base de datos
Figura 8
J4dvertenciaK3
Tener demasiadas conexiones activas en el entorno o configuradas en
l, puede incidir negativamente en el rendimiento de Visual Basic 2005
Express cuando se trabaja con l. Tenga configuradas slamente,
aquellas conexiones que va a utilizar, o aquellas conexiones de uso
ms habitual y frecuente.
134


%(dulo 1 ? Cap!tulo @
A. E;plorador de soluciones
El %&plorador de soluciones sera equivalente al %&plorador de +royecto en #isual Basic
G, y como en este ltimo, lo podemos encontrar en la parte derecha de nuestro
entorno de desarrollo.
Cabe destacar que en .NET hay una ligera diferencia con respecto a Visual Basic 6 que
conviene conocer. Un proyecto en #isual Basic 2BBC %&press equivale a una solucin.
Es quizs una caracterstica chocante al principio, pero en seguida nos
acostumbraremos a ello.
Una solucin se compone de proyectos y stos, de recursos y objetos. Por lo general,
una solucin contendr un proyecto, que equivaldra al mismo valor en Visual Basic 6,
pero podemos encontrarnos con ms de un proyecto dentro de una misma solucin.
Sin embargo, estos conceptos son muy sencillos de comprender y controlar, y para
nada debe hacernos pensar que esto es algo complejo que nos costar mucho tiempo
dominar. De hecho, la similitud con Visual Basic 6 es enorme.
En la figura 1, podemos observar la diferencia del explorador de soluciones entre
Visual Basic 6 y #isual Basic 2BBC %&press.
135
5plorador de proyectos en &isual #asic )
La opcin 5plorador de soluciones desple"ada en &isual
#asic ,++- 5press
Figura 1
Una caracterstica distinta en #isual Basic 2BBC %&press respecto a Visual Basic 6, es
que para agregar un nuevo formulario, clase, etc., en Visual Basic 6 bastaba con hacer
clic con el botn derecho del ratn sobre cualquier recurso del %&plorador de
soluciones, mientras que en el caso de #isual Basic 2BBC %&press, debemos hacer clic
con el botn derecho sobre la solucin. Adems, en #isual Basic 2BBC %&press,
tenemos ms opciones a aadir al proyecto que en Visual Basic 6.0.
Nota3
+ara abrir un recurso de la soluci<n3 basta con situarnos en el recurso
determinado3 por ejemplo un formulario 4indo!s de nombre
)ormH.b y "acer doble clic sobre :l. %l recurso se abrir@
autom@ticamente en #isual Basic 2BBC %&press.
*dem@s3 en #isual Basic 2BBC %&press sabremos en todo momento
sobre 9u: recurso estamos trabajando en un momento dado3 algo 9ue
al trabajar con proyectos grandes en #isual Basic G3 nos costaba un
gran esfuer.o.
136

%(dulo 1 ? Cap!tulo @
B. ,ropiedades
Esta es la parte del entorno de desarrollo que ms se parece a Visual Basic 6. Esta
ventana la encontraremos en la parte derecha y ms abajo de la ventana %&plorador
de soluciones en nuestro entorno de desarrollo.
Como en Visual Basic 6, esta ventana nos permitir acceder a las propiedades de los
objetos insertados en nuestros formularios Windows, como se muestra en la figura 1.
&entana de 9ropiedades de &isual #asic ) &entana de 9ropiedades de &isual #asic ,++- 5press
137
Figura 1
Para acceder a las propiedades de un determinado control, deberemos seleccionar el
control en el formulario Windows y acudir a la ventana -ropiedades, o bien como en
Visual Basic 6, seleccionar el control en el formulario Windows y pulsar el botn F=.

%(dulo 1 ? Cap!tulo @
3. %en)s y barra de botones
Respecto a los mens y barra de botones, tanto el entorno de Visual Basic 6 como el
entorno de #isual Basic 2BBC %&press, mantienen una similitud muy caracterstica,
aunque tambin hay algunas pequeas diferencias.
La variacin ms destacable es la accin de compilacin. Mientras en Visual Basic 6, la
opcin de compilacin la encontrbamos en el men 4rc?ivo 6 Oenerar, en #isual
Basic 2BBC %&press, esta opcin no slo cambia de lugar, sino que su filosofa tambin.
En este entorno de desarrollo, encontraremos esta opcin en el men Oenerar, y
dentro de este men, encontraremos diferentes opciones de compilacin y accin,
siempre sobre la Soluci<n o sobre el proyecto abierto.
Por otro lado, existe una manera de acceder a las partes ms importantes de nuestra
solucin de manera rpida.
Desde el men 8ro%ecto 6 8ropiedades, podemos acceder a las propiedades del
proyecto o solucin.
Existen diferentes apartados dentro de esta ventana que nos pueden resultar
especialmente tiles.
Uno de estos y relacionado con la opcin de compilacin es el apartado "o)pilar
como se muestra en la figura 1.
138
9ropiedades de la solucin sobre la que se trabaja en &isual #asic ,++- 5press
Figura 1
Como vemos en la figura 1, existen sin embargo multitud de opciones y apartados
diferentes relacionados todos ellos con nuestra solucin.
Otro de los apartados destacables, es el apartado denominado 8u#licar.
An as, ste es el corazn o parte fundamental que debemos controlar a la hora de
desarrollar una aplicacin o a la hora de gestionar una solucin, porque dentro de esta
ventana, se resume buena parte de los mens y barra de botones del entorno de
#isual Basic 2BBC %&press.
De todos los modos, tendremos la oportunidad de ver ms adelante, algunos usos de
algunas de las opciones de la barra de botones del entorno.
139

%(dulo 1 ? Cap!tulo @
C. $tras consideraciones
El desarrollador de Visual Basic 6, encontrar muy interesantes algunos de los cambios
incorporados en #isual Basic 2BBC %&press. Al principio, quizs se encuentre un poco
desorientado, pero rpidamente y gracias a su experiencia en el entorno Visual Basic
6, se acostumbrar al cambio. Entre algunos de estos cambios, destacara los
siguientes:
En #isual Basic 2BBC %&press, acceder a los objetos de nuestra aplicacin es
mucho ms fcil. Dentro del entorno, observaremos que se van creando
diferentes solapas que nos permite acceder y localizar los recursos con los que
estamos trabajando de forma rpida. En la figura 1 podemos observar
justamente esto que comento.
!olapas de los objetos abiertos en &isual #asic ,++- 5press
Figura 1
#isual Basic 2BBC %&press permite como en Visual Basic 6, hacer un .top / 0o
de nuestras aplicaciones, es decir, pausar la ejecucin de una aplicacin en
modo depuracin y modificar los valores o propiedades que deseemos y
continuar ejecutndola. Esta opcin que los programadores de Visual Basic 6
utilizan con mucha frecuencia en el desarrollo de sus aplicaciones, se ha
mantenido en #isual Basic 2BBC %&press, pero no en Visual Studio .NET 2002 y
Visual Studio .NET 2003. Si por alguna razn, debe trabajar con alguno de estos
entornos, debe saber que esta opcin no est disponible para las versiones
comentadas.
140
Otra caracterstica que debemos conocer de nuestro entorno de desarrollo, es la
capacidad de anclar o fijar una ventana de las comentadas anteriormente o de
permitir que se haga visible cuando acercamos el puntero del ratn sobre ella.
Esta opcin es la que puede verse en la figura 2.
:pcin de ocultar o mostrar la ventana seleccionada en &isual #asic ,++- 5press
Figura 2
Ntese que al pulsar sobre el icono indicado en la figura 2, haremos que esta ventana
quede fija en el entorno de desarrollo. Cuando pulsamos este icono, la ventana queda
fija y queda representado por un icono como el que se muestra en la figura 3.
Icono para ocultar o mostrar la ventana seleccionada cuando se encuentra en modo anclado
Figura 3
Algo que oculta el entorno de #isual Basic 2BBC %&press por defecto, son las
denominadas clases parciales.
Se trata de una nueva caracterstica aadida a .NET 2.0 y por lo tanto a Visual
Basic 2005, que permite separar o partir una clase en varias porciones de
cdigo.
La explicacin ruda de esto, es que el programador puede tener dos ficheros de cdigo
fuente independientes, que posean el mismo nombre de clase.
Para indicar que pertenece a la misma clase, sta debe tener la palabra clave -artial
como parte de su definicin para indicar que es una clase parcial.
Un ejemplo que aclare esto es el siguiente:
?!blic Class Class1
?!blic )!nction Accion1() As Integer
"et!rn 1
n% )!nction
n% Class
?artial ?!blic Class Class1
?!blic )!nction Accion2() As Integer
141
"et!rn 2
n% )!nction
n% Class
El comportamiento de la clase es el de una nica clase, por lo que su declaracin y uso
es como el de cualquier clase normal, tal y como se indica en el siguiente cdigo:
?!blic Class )orm1
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
Dim HiClase As AeJ Class1
Hessage,oG/ShoJ(HiClase/Accion2/1oString() P 5bCr'8 P
HiClase/Accion1/1oString())
n% S!b
n% Class
De todas las maneras, el entorno nos oculta muchas veces las clases parciales de un
aplicacin.
Para ello, pulsaremos sobre la opcin Mostrar todos los arc?ivos de la ventana
%&plorador de soluciones como se indica en la figura 4.
Icono u opcin para mostrar todos los arc%ivos del proyecto
Figura 4
De esta manera, podremos acceder a los archivos y recursos del proyecto, incluidas
las clases parciales como se indica en la figura 5.
142
Clase parcial mostrada en los arc%ivos del proyecto
Figura 5
4 tener en cuenta3
Cuando se genera un proyecto con #isual Basic 2BBC %&press3 el
entorno genera diferentes clases parciales3 como por ejemplo la 9ue
se genera para un formulario.

%(dulo 1 ? Cap!tulo 1
@. "atos
El grupo Datos corresponde con el grupo que tiene relacin directa con los
componentes de acceso a datos, como se muestra en la figura 1.
143
Controles Datos en &isual #asic ,++- 5press
Figura 1
Para el desarrollador de Visual Basic 6, los controles, componentes y mtodos de
acceso a datos, contiene dentro de s un especial misterio, es como el Santo 1rial de la
programacin. Casi siempre nos atascamos ah, siempre en el mismo sitio. Pero no se
preocupe ni lo ms mnimo por ello, aprenderemos a utilizarlos a base de prctica, y lo
que es ms importante, los dominaremos rpidamente gracias a nuestra experiencia
en Visual Basic 6. Slo como curiosidad y por ahora, le presentar uno de los
componentes ms destacables en #isual Basic 2BBC %&press, por su semejanza con
otro muy utilizado en Visual Basic 6 y versiones anteriores hasta Visual Basic 3, estoy
hablando del control y componente indin'+a$i'ator que usaremos frecuentemente
en nuestras aplicaciones con acceso a fuentes de datos.
Este control insertado en un formulario Windows, es el que se puede ver en la figura
2.
Control #indin";avi"ator insertado en un formulario 6indo7s en &isual #asic ,++- 5press
Figura 2
Como puede observar, este control, tiene un aspecto muy similar al del famoso
'ecordset de Visual Basic 6 tan utilizado por los desarrolladores de Visual Basic.
Lgicamente, este control tiene un aspecto mucho ms vistoso y moderno, pero es
uno de los controles estrella de #isual Basic 2BBC %&press, ya que inexplicablemente
en un primer momento por la Comunidad de desarrolladores que dieron el salto a
Visual Basic .NET, en Visual Studio .NET 2002 y Visual Studio .NET 2003 no exista
este control en el entorno.
144
Visual Studio 2005 y por lo tanto, Visual Basic 2005, s que nos trae sin embargo, la
novedad del control indin'+a$i'ator.
-omunidad dotNet3
#isual Studio 2BBC le proporciona un amplio conjunto de controles y
componentes asI como un no menos completo conjunto de clases 9ue
le facilita al desarrollador las tareas de programaci<n re9ueridas. Sin
embargo3 e&isten contribuciones gratuitas y otras de pago3 9ue el
programador puede utili.ar seg;n lo re9uiera. * continuaci<n le indico
el 9ue a mi modo de er es el lugar m@s representatio de este tipo de
contribuciones a la Comunidad de desarrolladores .$%T.
Microsoft GotDotNet


%(dulo 1 ? Cap!tulo 1
1. Componentes
#isual Basic 2BBC %&press, incluye un conjunto de componentes muy nutrido y
variado. Algunos de estos componentes, han sido mejorados y otros ampliados. En la
figura 1 podemos observar estos componentes.
145
Componentes de &isual #asic ,++- 5press
Figura 1
Los componentes son igual que los controles no visibles de Visual Basic 6. Para que lo
entienda mejor, el control Timer de Visual Basic 6 queda insertado en el formulario
como se indica en la figura 2.
Control $imer insertado en un formulario de &isual #asic )
Figura 2
En Visual Basic 2005, el comportamiento de los componentes, es ligeramente
diferente, como por ejemplo el mismo componente Timer de Visual Basic 2005.
Si hacemos doble clic sobre el componente Timer para insertarlo en el formulario, ste
quedar dispuesto en la parte inferior del formulario como se indica en la figura 3.
Control $imer insertado en un formulario de &isual #asic ,++-
Figura 3
Como en Visual Basic 6, este tipo de componentes no son visibles en tiempo de
ejecucin.
146


%(dulo 1 ? Cap!tulo 1
A. Controles comunes
Con este nombre, se aglutinan los controles ms generales y variados que podemos
utilizar en nuestras aplicaciones Windows. Sera algo as, como el resto de controles y
componentes no contenidos en ninguna de las secciones que hemos visto
anteriormente, aunque esto no es siempre as. Por esa razn, si encuentra dos
controles o componentes iguales en dos o ms secciones, no lo tenga en
consideracin.
Digamos que en esta solapa se aglutinan por lo tanto, los controles que utilizaremos
con ms frecuencia.
En la figura 1 podemos observar algunos de los controles y componentes citados.
147
Controles 6indo7s (orms en &isual #asic ,++- 5press
Figura 1
La cantidad de controles y componentes de esta seccin es de ms de 50. Una cifra
ms que suficiente para el desarrollador y enormemente superior al nmero de
controles y componentes que podamos utilizar en Visual Basic 6.
Truco3
Como puede obserar3 a eces cuesta locali.ar un control debido a la
enorme cantidad de controles 9ue "ay. +ara ordenarlos3 puede
arrastrar y soltar los controles y componentes en la barra de
"erramientas o bien3 si 9uiere "acer una ordenaci<n por orden
alfab:tico3 puede "acer clic con el bot<n derec"o del rat<n sobre una
determinada secci<n de controles y seleccionar la opci<n 1rdenar
ele)entos alfa!2tica)ente como se indica en la siguiente figura
siguiente=
148
Los controles y componentes de esa secci<n 9uedar@n ordenados
alfab:ticamente.
Lo ms destacable para el desarrollador de Visual Basic 6, es que aqu veremos una
gran cantidad de controles que nos resultarn muy familiares.
Controles como el control *a#el, 8ictureBo;, Te;tBo;, Frame que ahora pasa a
llamarse OroupBo;, -ommandButton que ahora pasa a llamarse Button,
-?ec!Bo;, 7ptionButton que ahora pasa a llamarse BadioButton, -om#oBo;,
*istBo;, 5ScrollBar, VScrollBar, Timer, etc.
Sin embargo, hay otro conjunto de controles nuevos para el desarrollador de Visual
Basic 6, y que proporciona nuevas y ventajosas caractersticas a la hora de desarrollar
aplicaciones con Visual Basic 2005.
Entre estos controles nuevos, podemos encontrar el control 8rint/ocument,
Error8rovider, Pe#Broser, 8rint8revie-ontrol, FolderBroser/ialo',
ToolTip que ahora debe insertarse para aportar tooltips a nuestros controles,
Trac!Bar, NumericGp/on, Split-ontainer, Mont?-alendar, /ateTime8ic!er,
etc.
Cada uno de los controles, tiene unas caractersticas y cualidades determinadas.
Slo a base de prctica, aprenderemos a utilizarlos y lo nico que debemos saber, es
cul de ellos utilizar en un momento dado.
El abanico de controles y componentes es lo suficientemente amplio como para poder
abordar con ellos, cualquier tipo de proyecto y aplicacin Windows que nos sea
demandada.
149

%(dulo 1 ? Cap!tulo 1
B. 5eneral
Esta seccin es como el cajn desastre, un lugar dnde podemos insertar otros
controles o componentes desarrollados por terceros por ejemplo.
!eccin <eneral en &isual #asic ,++- 5press
Figura 1
Esta seccin de todos los modos, la puede utilizar un desarrollador en muchos casos.
Por ejemplo, los desarrolladores que desean arrastrar y soltar aqu los controles y
componentes que ms utiliza o los que utiliza en un determinado proyecto.
Otro caso de ejemplo es cuando se trabaja con controles o componentes similares
desarrollados por dos empresas diferentes que queremos tener localizados o
separados para no mezclarlos.
150
En otras circunstancias, tampoco es raro encontrarse con controles o componentes con
iconos similares, por lo que aclararse cul es el que nos interesa puede ser una tarea
obligada.
An as, otra de las posibilidades con la que nos podemos encontrar para utilizar esta
seccin es la de tener que utilizar un control o componente circunstancialmente en un
momento dado, y por eso, que no deseemos aadir este control o componente a otra
seccin como la de Controles comunes por ejemplo.
Utilice por lo tanto esta seccin como lo considere oportuno.


%(dulo 1 ? Cap!tulo 1
3. $tras consideraciones
La seccin 1eneral nos indica un repositorio de mbito y carcter general, sin
embargo, el desarrollador puede querer ordenar su propio repositorio o seccin de
controles y componentes.


%anipulando el Cuadro de #erramientas
Para ello, nos posicionaremos en la barra de herramientas y pulsaremos el botn
derecho del ratn sobre la parte gris de la barra de herramientas desplegada y
seleccionaremos la opcin *gregar fic"a del men emergente, como se muestra en la
figura 1.
151
:pcin de personali4acin de nuestros propios "rupos de controles y componentes
Figura 1
Cuando seleccionamos esta opcin, aparecer una caja de texto en la barra de
herramientas dnde podremos escribir el nombre que consideremos oportuno, como
se muestra en la figura 2.
152
9ersonali4acin de un "rupo de controles y componentes en &isual #asic ,++- 5press
Figura 2
Si se hace la siguiente pregunta, cmo cambiar el nombre de una seccin ya creada o
una existente?, sepa que deber realizar los siguiente pasos.
Haga clic con el botn derecho del ratn sobre la seccin sobre la que desea cambiar
el nombre y seleccione la opcin "a)!iar no)!re de fic,a como se muestra en la
figura 3.
Figura 3
De igual forma, puede cambiar tambin el nombre de los controles o componentes
insertados.
Para hacer eso, haga clic con el botn derecho del ratn sobre un control o
componente y seleccione la opcin "a)!iar no)!re de ele)ento como se muestra
en la figura 4.
153
Figura 4
Visual Basic 2005, nos proporciona un amplio conjunto de opciones de personalizacin
del entorno de trabajo, para que se ajuste a las exigencias de los desarrolladores. A
diferencia de Visual Basic 6, el nmero de opciones y posibilidades de Visual Basic
2005, es mucho ms alto como hemos podido ver.
F4N3
Qu ocurre si me equivoco personalizando mi barra de herramientas?
#isual Basic 2BBC %&press nos proporciona la posibilidad de resetear o
restaurar el estado inicial de la barra de "erramientas en el entorno de
desarrollo. +ara "acer esto3 "aremos clic con el bot<n derec"o del
rat<n la barra de "erramientas y seleccionaremos la opci<n
3esta!lecer cuadro de ,erra)ientas del men; emergente3 como
se muestra en la siguiente figura.
154
J7(oK, al seleccionar esta opcin, perderemos todas las modificaciones
que hayamos realizado sobre la barra de herramientas.


$tros controles a tener en cuenta
Dentro del entorno de #isual Basic 2BBC %&press y en .NET en general, se han aadido
una serie de controles nuevos que conviene comentar.
Uno de estos controles, se llama 4ebBro!ser, tal y como se indica en la figura 5.
Control 6eb#ro7ser en el Cuadro de %erramientas
Figura 5
Este control es la representacin de un control especfico para mostrar contenido XML
o contenido HTML, como si de una pgina web se tratara.
155
Sirva el siguiente ejemplo de cdigo fuente para demostrar como usar el control y
como se muestra dicho control en una aplicacin Windows.
El cdigo de la aplicacin quedara como se detalla a continuacin:
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As 0b#ect, ,-$al e As
S-stem/5entArgs) Han%les He/'oa%
<eb,roJser1/Aa5igate("htt2DVVlocalhostV,ien5eni%o/as2")
n% S!b
n% Class
Nuestro ejemplo en ejecucin es el que se muestra en la figura 6.
Control 6eb#ro7ser en ejecucin
Figura 6
Hay ms controles que representan una novedad para el desarrollador de .NET, pero
no tanto para el desarrollador de Visual Basic 6, como puede ser por ejmplo, el control
Mas!edTe;tBo;, como se muestra en la figura 7.
Control Mas=ed$e5t#o5 en &isual #asic ,++-
Figura 7
156
Sin embargo, hay otros controles clsicamente demandados por los desarrolladores,
como los controles de accesos a puertos COM y puertos serie, como es el caso del
control Serial8ort que se muestra en la figura 8.
Control !erial9ort en &isual #asic ,++-
Figura 8
No es cuestin de repasar cada uno de los controles que el programador puede
encontrar en #isual Basic 2BBC %&press, sin embargo, no me gustara dejar de
comentar, uno de los controles ms usados y tiles para las aplicaciones Windows, que
tiene a su vez su equivalente para el desarrollo de aplicaciones Web en ASP.NET. Me
refiero al control Mont?-alendar que se muestra en la figura 9.
Control Mont%Calendar en &isual #asic ,++-
Figura 9
Este control, que se muestra en la figura 10 cuando lo insertamos en un formulario, es
un control que nos facilita la entrada de fechas en el sistema y permite asegurarnos,
que la fecha seleccionada es una fecha vlida.
Control Mont%Calendar insertado en un formulario 6indo7s
Figura 10
157


-ntroducci(n
Hasta ahora, hemos aprendido a identificar las partes ms importantes del entorno de
desarrollo de #isual Basic 2BBC %&press, hemos visto igualmente como se separan los
controles y componentes, y hemos visto tambin que existe un grupo de solapas
dnde podramos aadir nuestros propios controles y componentes, incluso hemos
aprendido a crear nuestro propio grupo o seccin de controles y componentes, dnde
podemos tambin incluir los controles y componentes que por ejemplo hayamos
desarrollado nosotros mismos, sin embargo, para poder insertar ah un control o
componente desarrollado por nosotros, deberamos aprender a crearlos.
Eso es justamente lo que veremos a continuacin adems de ver otras tcnicas que
conviene repasar antes de aprender a desarrollar nuestros propios controles y
componentes.
Por eso, lo primero que haremos ser aprender a desenvolvernos adecuadamente en
el entorno de desarrollo con los controles que ya conocemos.
%(dulo 1 ? Cap!tulo A

1. Dominando los controles en el entorno de trabajo
2. Creacin de controles en tiempo de ejecucin
3. Creacin de una matriz de controles
4. Creacin de controles nuevos
5. Otras consideraciones

158

%(dulo 1 ? Cap!tulo A
@. "ominando los controles en el entorno de trabao
Si queremos aprender a acrear nuestros propios controles para poder distribuirlos y
utilizarlos en nuestro entorno, lo mejor es dominar el uso de los controles en nuestro
entorno de desarrollo.
Ya hemos visto anteriormente como insertar un control a nuestro formulario, pero
quizs no sepamos como manejarlos de forma eficiente en nuestro formulario.
Inserte en un formulario Windows por ejemplo, tres controles Button como se
muestra en la figura 1.
159
Controles #utton insertados en un formulario 6indo7s
Figura 1
Como podemos observar, los controles estn dispuestos de una forma desordenada, ya
que al insertarlos por ejemplo haciendo doble clic tres veces sobre un control Button,
stos quedan dispuestos anrquicamente en el formulario.
Separe los controles Button de forma que queden ahora esparcidos en el formulario
de alguna manera tal y como se muestra en la figura 2.
Controles #utton separados en el formulario
Figura 2
160
Seleccione todos los controles Button como se mostraba en la figura 2 y seleccione
del men las opciones Formato 6 4linear 6 *ados i@&uierdos como se indica en la
figura 3.
Los controles #utton quedar>n ordenados correctamente dentro del formulario
Figura 3
Sin embargo, podemos extender el uso de las propiedades especiales para alinear los
controles en un formulario.
Por ejemplo, ahora que tenemos los controles Button alienados correctamente,
podemos hacer uso de la opcin de men Formato 6 Espaciado vertical 6 Nuitar
como se indica en la figura 4.
:tras opciones especiales8 nos permiten alinear o trabajar con los controles de forma r>pida y se"ura
Figura 4
En este caso, los controles quedarn dispuestos en el formulario como se indica en la
figura 5.
161
Controles alineados y espaciados se"?n la eleccin de opciones del entorno
Figura 5
Como podemos apreciar, alinear los controles en el entorno es realmente sencillo.
Visual Basic 2005 Express nos proporciona una gran cantidad de opciones para llevar a
cabo este tipo de tareas.
Incluso si nos encontramos con un controles de diferente tamao entre s como se
muestra en la figura 6, podemos hacer uso de la opcin del men Formato 6 I'ualar
tamaQo permitindonos cambiar el tamao de los controles seleccionados dentro del
formulario Windows.
162
Controles de diferentes tama2os dispuestos en el formulario 6indo7s
Figura 6
El men que nos permite cambiar los tamaos de los controles insertados en un
formulario posee diferentes posibilidades.
En nuestro caso, seleccionaremos del men, la opcin Formato 6 I'ualar tamaQo 6
4m#os tal y como se muestra en la figura 7.
Cambiando los tama2os anc%o y alto de los controles seleccionados de un formulario
Figura 7
Una vez seleccionada esta opcin, los controles se modificarn con el mismo tamao
tal y como se muestra en la figura 8.
163
Controles del formulario con su tama2o modificado
Figura 8
Una vez seleccionada esta opcin, los controles se modificarn con el mismo tamao
tal y como se muestra en la figura 8.
Truco3
Suponiendo 9ue tengamos tres controles utton de diferentes
tamaAos y 9ue 9ueramos 9ue todos tengan el mismo tamaAo 9ue el
segundo de sus controles3 seleccionaremos sie)pre como primer
control3 el control 9ue 9ueremos como base de tamaAo para el resto
de controles3 y posteriormente con la tecla "trl seleccionaremos uno a
uno el resto de controles.
Sin embargo, para alinear los controles en un formulario tenemos ms opciones.
Hemos visto algunas de ellas, quizs las ms habituales, pero como podemos deducir
del men Formato, podremos alinear los controles, espaciarlos entre s horizontal o
verticalmente, modificar su tamao, centrarlos en el formulario horizontal o
verticalmente, etc.
Por otro lado, Visual Basic 2005 Express, nos proporciona una utilidad en tiempo de
diseo muy til.
Se trata de las guas de representacin que veremos en tono azul claro, y que
aparecen cuando movemos un control en el formulario.
Estas guas indican la situacin y posicin de un control respecto a otro prximo.
La representacin de estas guas que se muestran en la figura 9, nos facilita
enormemente la disposicin de los controles en un formulario.
<u@as o re"las de direccin o separacin entre controles
Figura 9

164

%(dulo 1 ? Cap!tulo A
1. Creaci(n de controles en tiempo de eecuci(n
Prcticamente todo en .NET son objetos. Los controles tambin, as que para aadir un
control a un formulario en tiempo de ejecucin, deberemos hacerlo tratndolo como
un objeto.
La declaracin principal de un objeto, se realiza con la clasula Ne.
El siguiente ejemplo de cdigo, crea un control Button en tiempo de ejecucin.
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos el ob#eto ,!tton
Dim HiControl As AeJ ,!tton
4 Declaramos !n nombre al control (si I!eremos)
HiControl/Aame = "btn1"
4 Cambiamos alg!nas %e s!s 2ro2ie%a%es
HiControl/1eGt = "#em2lo %e ,otSn"
HiControl/1o2 = 50
HiControl/'e8t = 50
HiControl/<i%th = 200
165
HiControl/Height = 50
4 ATa%imos el control al )orm!lario
He/Controls/A%%(HiControl)
n% S!b
En la figura 1 podemos ver el resultado en ejecucin del cdigo escrito anteriormente.
Para ejecutar nuestra aplicacin, pulsaremos el botn F5 como lo hemos hecho
siempre en Visual Basic 6.
Creacin de un control en tiempo de ejecucin en &isual #asic ,++-
Figura 1
Otra de las caractersticas de los controles tanto para los programadores de Visual
Basic 6 como para los programadores que comienzan con Visual Basic 2005, es la
posibilidad de manipular los controles en tiempo de ejecucin. Sin embargo, en
nuestro caso, vamos a modificar la propiedad Te;t del control Button que hemos
insertado en tiempo de ejecucin.
Para hacer esto, lo ms habitual es poner el nombre del control, su propiedad y el
valor correspondiente. En nuestro caso, el cdigo quedara como el que se indica a
continuacin:
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos el ob#eto ,!tton
Dim HiControl As AeJ ,!tton
4 Declaramos !n nombre al control (si I!eremos)
HiControl/Aame = "btn1"
4 Cambiamos alg!nas %e s!s 2ro2ie%a%es
166
HiControl/1eGt = "#em2lo %e ,otSn"
HiControl/1o2 = 50
HiControl/'e8t = 50
HiControl/<i%th = 200
HiControl/Height = 50
4 ATa%imos el control al )orm!lario
He/Controls/A%%(HiControl)
4 Ho%i8icamos la 2ro2ie%a% 1eGt %el control inserta%o
btn1/1eGt = "0tro teGto"
n% S!b
Analizando este cdigo, parece estar bien escrito, pero al pulsar F5 para ejecutar
nuestro proyecto, nos encontramos con que Visual Basic 2005 nos muestra un error.
Nos indica que !tn1 no est declarado. Qu ocurre?. Al buscar la clase de
ensamblados de la aplicacin, el control Button de nombre !tn1 no existe, por lo que
Visual Basic 2005 detecta que debemos declarar el control, sin embargo y en nuestro
caso, esta declaracin la hacemos en tiempo de ejecucin. Cmo acceder a la
propiedad Te;t del control Button creado en tiempo de ejecucin?.
El siguiente cdigo resuelve esta duda:
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos el ob#eto ,!tton
Dim HiControl As AeJ ,!tton
4 Declaramos !n nombre al control (si I!eremos)
HiControl/Aame = "btn1"
4 Cambiamos alg!nas %e s!s 2ro2ie%a%es
HiControl/1eGt = "#em2lo %e ,otSn"
HiControl/1o2 = 50
HiControl/'e8t = 50
HiControl/<i%th = 200
HiControl/Height = 50
4 ATa%imos el control al )orm!lario
He/Controls/A%%(HiControl)
167
4 Ho%i8icamos la 2ro2ie%a% 1eGt %el control inserta%o
C1-2e(He/)in%)orm/Controls("btn1"), ,!tton)/1eGt = "0tro teGto"
n% S!b
Bsicamente, utilizamos la funcin -T%pe para buscar en el formulario principal, el
control Button de nombre !tn1, para poder as, cambiar la propiedad Te;t de este
control.
An as, tambin podramos haber accedido a la propiedad Te;t del control mediante
otra accin complementaria, como se muestra en el siguiente cdigo:
4 Declaramos el ob#eto ,!tton
Dim HiControl As AeJ ,!tton
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos !n nombre al control
HiControl/Aame = "btn1"
4 Cambiamos alg!nas %e s!s 2ro2ie%a%es
HiControl/1eGt = "#em2lo %e ,otSn"
HiControl/'ocation = AeJ ?oint(50, 50)
HiControl/Si&e = AeJ Si&e(200, 50)
4 ATa%imos el control al )orm!lario
He/Controls/A%%(HiControl)
n% S!b
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
HiControl/1eGt = "0tro teGto"
n% S!b
J7(oK3
Tenga en cuenta 9ue esta acci<n se puede reali.ar si la declaraci<n del
objeto utton est@ dentro del mismo @mbito de llamada de la
propiedad 4e&t. +or esa ra.<n3 "emos sacado la declaraci<n (iControl
del objeto utton fuera del procedimiento de creaci<n din@mica del
control3 pero tenga en cuenta tambi:n3 9ue en este caso3 tendremos
168
declarada siempre en memoria la ariable (iControl. %l uso de la
funci<n "45pe es siempre m@s seguro.
El caso anterior utilizando nicamente la funcin -T%pe quedara como se detalla a
continuacin (para este ejemplo, he aadido adems un control Button al formulario
4indo!s, desde el cul cambiaremos la propiedad Te;t del control Button creado en
tiempo de ejecucin):
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos el ob#eto ,!tton
Dim HiControl As AeJ ,!tton
4 Declaramos !n nombre al control (si I!eremos)
HiControl/Aame = "btn1"
4 Cambiamos alg!nas %e s!s 2ro2ie%a%es
HiControl/1eGt = "#em2lo %e ,otSn"
HiControl/'ocation = AeJ ?oint(50, 50)
HiControl/Si&e = AeJ Si&e(200, 50)
4 ATa%imos el control al )orm!lario
He/Controls/A%%(HiControl)
n% S!b
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
C1-2e(He/)in%)orm/Controls("btn1"), ,!tton)/1eGt = "0tro teGto"
n% S!b
Este ejemplo en ejecucin es el que se muestra en la figura 2.
169
jecucin del ejemplo anterior en &isual #asic ,++-
Figura 2
Antes de continuar con el siguiente apartado en el que aprederemos a crear un array
de controles, comentar que a la hora de posicionar un determinado control en un
formulario 4indo!s, lo podemos hacer con las propiedades Top y *eft, o bien,
utilizando la propiedad *ocation. Lo mismo ocurre con las propiedades Pidt? y
5ei'?t que pueden ser sustituidas por la propiedad Si@e.
El mismo ejemplo de creacin de controles en tiempo de ejecucin utilizando el
mtodo *ocation y Si@e, quedara como se detalla a continuacin:
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos el ob#eto ,!tton
Dim HiControl As AeJ ,!tton
4 Declaramos !n nombre al control (si I!eremos)
HiControl/Aame = "btn1"
4 Cambiamos alg!nas %e s!s 2ro2ie%a%es
HiControl/1eGt = "#em2lo %e ,otSn"
4 ?ro2ie%a% 'ocation
HiControl/'ocation = AeJ ?oint(50, 50)
4 ?ro2ie%a% Si&e
HiControl/Si&e = AeJ Si&e(200, 50)
4 ATa%imos el control al )orm!lario
170
He/Controls/A%%(HiControl)
n% S!b
Hasta ahora hemos visto como crear controles en tiempo de ejecucin, pero en
muchas ocasiones, nos es til no slo crear un control en tiempo de ejecucin, sino
relacionarlo con un evento.
En nuestro ejemplo del control Button, cuando hacemos clic sobre el control, no
ocurre nada, y sera interesante mostrar un mensaje o realizar una accin
determinada.
Para hacer esto, deberemos utilizar el mtodo Add6andler para asignar un evento al
control creado dinmicamente. El cdigo de nuestro ejemplo mejorado es el que se
detalla a continuacin:
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos el ob#eto ,!tton
Dim HiControl As AeJ ,!tton
4 Declaramos !n nombre al control (si I!eremos)
HiControl/Aame = "btn1"
4 Cambiamos alg!nas %e s!s 2ro2ie%a%es
HiControl/1eGt = "#em2lo %e ,otSn"
HiControl/'ocation = AeJ ?oint(50, 50)
HiControl/Si&e = AeJ Si&e(200, 50)
4 ATa%imos el control al )orm!lario
He/Controls/A%%(HiControl)
4 ATa%imos el e5ento ClicQ al control crea%o %in6micamente
A%%Han%ler HiControl/ClicQ, A%%ress08 btn1ClicQ
n% S!b
?!blic S!b btn1ClicQ(,-$al Sen%er As 0b#ect, ,-$al e As S-stem/5entArgs)
4 Hostramos !n Hensa#e
Hessage,oG/ShoJ("So- el Control ,!tton con teGtoD 4" B
C1-2e(C1-2e(Sen%er, ,!tton)/1eGt, String) B "4")
n% S!b
Nuestro ejemplo en ejecucin es el que se muestra en la figura 3.
171
jecucin del ejemplo con asociacin de evento desarrollado en &isual #asic ,++-
Figura 3


%(dulo 1 ? Cap!tulo A
A. Creaci(n de una matri* de controles
En el captulo anterior, hemos visto como crear controles en tiempo de ejecucin e
incluso como asociar un evento a un control creado dinmicamente en Visual Basic
2005, pero, qu ocurre si queremos crear un array o matriz de controles como
hacamos en Visual Basic 6?.
La respuesta en este caso no puede ser peor. No se puede.
172
Bueno, en realidad s se puede, pero emulando o simulndolo. El hecho de que no se
pueda no es porque Visual Basic 6 sea mejor que Visual Basic 2005, sino precisamente
todo lo contrario. Visual Basic 6 tena una carencia en el tratamiento de los objetos
(hay que recordar que Visual Basic 6 no es un lenguaje de programacin orientado a
objetos) y en muchos casos, simulaba acciones de orientacin a objetos que chocaban
con la autntica naturaleza del entorno de Visual Basic. Esa carencia est superada por
Visual Basic 2005 y obviamente y por eso, algunas cosas y modos de trabajar cambian
como estamos viendo.
Recordemos que en Visual Basic 6 podamos crear una matriz de controles gracias al
uso de la propiedad Inde;. De esa manera, podamos tener por ejemplo un control de
nombre 4e&t1708 y otro control de nombre 4e&t1718.
En Visual Basic 2005 la propiedad Inde; no existe. Esto significa que para usar una
matriz de controles en Visual Basic 2005 deberemos simular la accin de Inde;.
Podemos simular una matriz de controles de muchas formas. Yo en este ejemplo,
aplicar la siguiente forma de llevar a cabo esta tarea:
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos la 5ariable conta%or %el b!cle ?ara
Dim I As ,-te
4 Declaramos la 5ariable conta%or %el nWmero %e controles a crear
Dim intA!mControles As ,-te = 5
4 Iniciamos el b!cle ?ara
)or I = 0 1o intA!mControles C 1
4 Declaramos el ob#eto 1eGt,oG
Dim HiControl As AeJ 1eGt,oG
4 'e asignamos !n nombre al control
HiControl/Aame = "tGt1"
4 Ftili&amos la 2ro2ie%a% 1ag 2ara almacenar ahK el 5alor %el
control %e la matri& 5irt!al
HiControl/1ag = I
4 'e asignamos !n tamaTo en el )orm!lario <in%oJs
HiControl/Si&e = AeJ Si&e(100, 20)
4 'e asignamos !na 2osiciSn en el 8orm!lario <in%oJs
HiControl/'ocation = AeJ ?oint(50, 22 O (I B 1))
4 'e cambiamos la 2ro2ie%a% 1eGt
HiControl/1eGt = HiControl/Aame B "(" B I/1oString() B ")"
173
4 ATa%imos el control al )orm!lario
He/Controls/A%%(HiControl)
4 ATa%imos el e5ento ClicQ al control crea%o %in6micamente
A%%Han%ler HiControl/ClicQ, A%%ress08 tGt1ClicQ
AeGt
n% S!b
?!blic S!b tGt1ClicQ(,-$al Sen%er As 0b#ect, ,-$al e As S-stem/5entArgs)
4 Hostramos !n Hensa#e
Hessage,oG/ShoJ("Control " B C1-2e(Sen%er, 1eGt,oG)/1ag/1oString())
n% S!b
Nuestro ejemplo de demostracin en ejecucin es el que se puede ver en la figura 1.
jecucin de la simulacin de una matri4 de controles
Figura 1
Obviamente, existen diferentes formas y tcnicas de simular un array o matriz de
controles. Sirva esta que hemos visto, como ejemplo de lo que se puede hacer, pero
para nada se trata de una norma o regla fija.
Debemos destacar que en .NET no existe el concepto de array o matriz de controles
como en Visual Basic 6, por lo que sta, es una caracterstica no propia del lenguaje,
pero que para los desarrolladores que vienen de Visual Basic 6 anterior, conviene
conocer.
174

%(dulo 1 ? Cap!tulo A
B. Creaci(n de controles nuevos
Ya hemos visto la diferencia ms genrica entre un componente y un control, pero an
no sabemos como desarrollar nuestros propios controles en Visual Basic 2005.
En primer lugar y antes de adentrarnos en la creacin de nuestros propios controles
con Visual Basic 2005, debo indicarle que debemos obviar todo lo relacionado con los
ActiveX OCX y ActiveX en general.
En Visual Basic 2005, la palabra ActiveX ya no existe. El modelo de programacin ha
cambiado y por eso, los componentes y controles se generan ahora siguiendo otras
normas que aprenderemos a utilizar de forma inmediata.
Iniciaremos #isual Basic 2BBC %&press y seleccionaremos un proyecto de tipo
Bi#lioteca de clases. En el nombre de proyecto, podemos indicarle el nombre que
deseemos tal y como se muestra en la figura 1, y a continuacin pulsaremos el botn
7R.
175
!eleccin de nuevo proyecto #iblioteca de clases en &isual #asic ,++-
Figura 1
La diferencia mayor que reside entre el desarrollo de componentes y controles en
.NET, es que en lugar de heredar de la clase -omponent como en el caso de la
creacin de los componentes, se ha de heredar de la clase -ontrol o
S%stem.Pindos.Forms.Gser-ontrol.
El tipo de proyecto seleccionado no posee por defecto como en Visual Basic 6, la
superficie contenedora sobre la cul podremos insertar otros controles o realizar las
acciones que consideremos pertinentes para crear as nuestro control personalizado.
En este caso, la superficie contenedora la deberemos crear aadiendo las referencias
necesarias a nuestro programa.
Haga clic con el botn derecho del ratn sobre el proyecto o solucin de la ventana
E;plorador de soluciones y a continuacin, seleccione la opcin 8ropiedades del
men emergente.
A continuacin, agrege las referencias a las libreras de clases S%stem./rain' y
S%stem.Pindos.Forms.
Por ltimo, escriba las siguientes instrucciones bsicas.
Im2orts S-stem/Com2onentHo%el
Im2orts S-stem/<in%oJs/)orms
Im2orts S-stem/DraJing
176
?!blic Class Class1
Inherits FserControl
n% Class
En este punto, nuestra clase habr sido transformada en la clase contenedora de un
control que es la que puede verse en la figura 2.
!uperficie contenedora por defecto de un control
Figura 2
An as, sino quiere realizar esta accin, otra forma de tener lista la superficie
contenedora del control, es la de eliminar la clase del proyecto y pulsar el botn
derecho del ratn sobre la ventana del %&plorador de soluciones y seleccionar la
opcin de 4're'ar 6 Nuevo elemento... del men emergente.
De las opciones que salen, deberamos seleccionar entonces la plantilla -ontrol de
usuario.
Sin ms dilacin, y teniendo en cuenta que nuestro control posee una clase principal y
una clase parcial, aunque podramos aglutinar todo el cdigo en la clase principal,
aadiremos sobre la superficie del control contenedor, dos controles Label y dos
controles Te&tBo&.
A continuacin, escribiremos el siguiente cdigo:
Im2orts S-stem/Com2onentHo%el
Im2orts S-stem/<in%oJs/)orms
?!blic Class HiControl
?ri5ate +Acceso As ,oolean
177
(Categor-("Acceso"), Descri2tion("In%ica si se 2ermite o no el acceso"),
De8a!lt$al!e(")alse"), 9"ea%0nl-:(1r!e)* +
?!blic ?ro2ert- Acceso() As ,oolean
;et
"et!rn +Acceso
n% ;et
Set(,-$al $al As ,oolean)
+Acceso = $al
n% Set
n% ?ro2ert-
?ri5ate S!b FserControl1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
+Acceso = )alse
n% S!b
?!blic S!b $ali%ar()
I8 1eGt,oG1/1eGt = "e#em2lo" An% 1eGt,oG2/1eGt = "e#em2lo" 1hen
+Acceso = 1r!e
lse
+Acceso = )alse
n% I8
n% S!b
n% Class
Observando el cdigo, vemos que hemos creado una propiedad 4cceso que nos
permitir saber si un usuario y contrasea han sido validadas o no.
Ahora nuestro control, est listo ya para ser compilado y probado en una aplicacin
Windows.
Para compilar nuestro control, haga clic en el men Oenerar 6 Oenerar
-lass*i#rar%$ como se muestra en la figura 3.
178
:pcin para compilar nuestro control
Figura 3
A continuacin aada un nuevo proyecto 4plicacin para Pindos a la solucin y
establzcalo como proyecto inicial de la solucin. Acuda a la barra de herramientas y
busque el control que hemos creado y compilado para insertarlo en el formulario
Windows. Sino aparece en la barra de herramientas, deber aadirlo de la siguiente
manera.
Haga clic sobre la barra de herramientas y seleccione la opcin Ele'ir Elementos...
del men emergente que aparece en la figura 4.
:pcin para a2adir un control o componente a la barra de %erramientas
Figura 4
Aparecer una ventana para buscar el control ya compilado en el disco duro.
Pulsaremos el botn E;aminar... y buscaremos nuestro control para seleccionarlo.
Una vez hecho esto, tal y como se indica en la figura 5, haremos clic sobre el botn
7R.
179
!eleccin del control compilado anteriormente
Figura 5
Nuestro control quedar insertado en en la barra de herramientas como se muestra en
la figura 6.
Control insertado en la barra de %erramientas
180
Figura 6
Para insertar el control en el formulario, haremos doble clic sobre l. Este quedar
dispuesto en el formulario Windows como se indica en la figura 7.
Control insertado en el formulario 6indo7s de prueba
Figura 7
Nuestro formulario Windows de prueba en ejecucin con el control insertado en l, es
el que puede verse en la figura 8.
(ormulario 6indo7s de prueba en ejecucin con el control insertado
Figura 8
Como ha podido comprobar, la creacin de controles en Visual Basic 2005, tampoco
requiere de una gran habilidad o destreza, y su similitud con la creacin de
componentes es enorme. De hecho, todo se reduce en el uso y programacin de una
clase con la salvedad de que dentro de esa clase, indicamos si se trata de una clase
como tal, la clase de un componente o la clase de un control.

181

-ntroducci(n
Trabajar con grficos e imgenes es una de las particularidades aadidas a Visual
Basic 2005 y que ms ha cambiado respecto a Visual Basic 6.
En este captulo veremos las partes ms generales en el uso y generacin de imgenes
y grficos con Visual Basic 2005.
Pasaremos de puntillas sobre el uso de DirectX para la generacin de grficos 3D y nos
adentraremos un poco ms profundamente, en el desarrollo de grficos e imgenes 2D
con GDI+.
%(dulo 1 ? Cap!tulo B

1. Grficos 3D
2. Grficos 2D
3. Dibujando lneas con GDI+
4. Dibujando curvas con GDI+
5. Dibujando cadenas de texto con GDI+
6. Otras consideraciones
182

%(dulo 1 ? Cap!tulo B
@. 5r&ficos A"
Para trabajar con imgenes y grficos en 3D, deberemos utilizar DirectX, ya que
dentro de la plataforma .NET de Microsoft, no tenemos la posibilidad de crear
representaciones 3D.
Esto significa por otra parte, que si desarrollamos una aplicacin con representacin
3D con DirectX, deberemos distribuir tambin las libreras DirectX en la mquina en la
que se ejecute nuestra aplicacin. Es decir, no bastar con distribuir Microsoft .NET
Framework.
Pero DirectX no nos permite slo crear grficos e imgenes en 3D, tambin podemos
crear imgenes en 2D, pero lo ms normal en este ltimo caso y salvo que no
requeramos un uso continuado de DirectX, ser utilizar en su lugar GDI+, como
veremos ms adelante.
Para trabajar con DirectX en Visual Basic 2005, deberemos aadir una referencia al
proyecto con la librera o libreras COM de DirectX, eso si trabajamos con DirectX 8 o
anterior, ya que a partir de DirectX 9, Microsoft ha proporcionado un conjunto de
clases y libreras que interactan con .NET directamente, permitindonos ejecutar
aplicaciones .NET con DirectX administrado.
En nuestro caso, lo mejor es realizar un ejemplo, no sin antes recordar, que debera
descargar Microsoft DirectX SDK 9 e instalarlo en su sistema.
El SDK contiene ficheros de ayuda y documentacin que le ensear a crear
aplicaciones con DirectX 9 en Visual Basic 2005.
F4N3
Dnde puedo descargar Microsoft DirectX 9.0 SDK?
La ;ltima ersi<n de DirectJ SDK la encontrar@ en la p@gina !eb de
(SD$ de DirectJ3 especialmente creada para desarrolladores de
183
aplicaciones y juegos.
Descargas de Microsoft DirectX
Una vez que tenemos instalado en nuestro sistema las libreras de desarrollo de
DirectX para .NET, iniciaremos una nueva aplicacin Windows, aadiremos las
referencias a las libreras (icrosoft.DirectJ y (icrosoft.DirectJ.Direct3D tal y como se
muestra en la figura 1 y las cules encontraremos normalmente en el directorio
c=L!indo!sLsystem32L.
3eferencias a DirectA a2adidas a nuestro proyecto
Figura 1
A continuacin, escribiremos el siguiente cdigo:
Im2orts Hicroso8t/DirectL
Im2orts Hicroso8t/DirectL/Direct3D
?!blic Class )orm1
?!blic S!b CreateDe5ice()
Dim 22 As AeJ ?resent?arameters()
22/<in%oJe% = 1r!e
22/SJa288ect = SJa288ect/Discar%
Dim %5 As AeJ De5ice(0, De5ice1-2e/Har%Jare, He,
Create)lags/So8tJare$erteG?rocessing, 22)
184
Dim 5ertices(6) As C!stom$erteG/1rans8orme%Colore%
5ertices(0)/Set?osition(AeJ $ector.(He/<i%th V 2/0), N0/0), 0/5),
1/0)))
5ertices(1)/Set?osition(AeJ $ector.(He/<i%th C (He/<i%th V 5/0)),
He/Height C (He/Height V 5/0)), 0/5), 1/0)))
5ertices(2)/Set?osition(AeJ $ector.(He/<i%th V 5/0), He/Height C
(He/Height V 5/0)), 0/5), 1/0)))
5ertices(3)/Set?osition(AeJ $ector.(He/<i%th V 2/0), 50/0), 0/5),
1/0)))
5ertices(.)/Set?osition(AeJ $ector.(He/<i%th C (He/<i%th V 5/0)),
He/Height C (He/Height V 5/0)), 0/5), 1/0)))
5ertices(5)/Set?osition(AeJ $ector.(He/<i%th V 5/0), He/Height C
(He/Height V 5/0)), 0/5), 1/0)))
%5/Clear(Clear)lags/1arget, S-stem/DraJing/Color/,l!e$iolet, 2/0), 0)
%5/,eginScene()
%5/$erteG)ormat = $erteG)ormats/1rans8orme%
%5/DraJFser?rimiti5es(?rimiti5e1-2e/1riangle'ist, 2, 5ertices)
%5/n%Scene()
%5/?resent()
n% S!b
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
CreateDe5ice()
n% S!b
n% Class
Este pequeo ejemplo demostrativo en ejecucin del uso de DirectX desde nuestras
aplicaciones Visual Basic 2005, es el que puede verse en la figura 2
185
jemplo de DirectA con &isual #asic ,++- en ejecucin
Figura 2


%(dulo 1 ? Cap!tulo B
1. 5r&ficos 1"
Las APIs de GDI+ corresponden a la evolucin natural de las APIs y libreras GDI que
se utilizaban en otros lenguajes de desarrollo. GDI+ no es otra cosa que un conjunto
186
de clases desarrolladas para el entorno .NET y por esa razn, podemos entonces
dibujar y crear representaciones grficas en Visual Basic 2005.
Todas las clases GDI+, pueden ser localizadas a travs del nombre de espacio
S%stem./rain'. As, podemos acceder a todas las posibilidades que nos ofrece
GDI+ y las cuales veremos ms adelante.
GDI+, no accede al hardware directamente, interacta con los driers de los
dispositivos grficos. Como particularidad, debemos saber que GDI+ est soportado
por Win32 y Win64.
Respecto a los sistemas operativos y el soporte de estos para GDI+, Windows XP
contiene la librera 'diplus*dll que encontraremos normalmente en
c=L!indo!sLsystem32L y la cul nos permite trabajar con GDI+. Microsoft .NET por
otra parte, nos proporciona el acceso directo a esta librera para poder desarrollar
nuestras aplicaciones de forma mucho ms cmoda y sencilla.
F4N3
Dispone mi sistema operativo de GDI+?
(icrosoft .$%T )rame!or6 instala autom@ticamente en su sistema las
librerIas 1DIM para 9ue las pueda utili.ar en sus aplicaciones.
Descargas de Microsoft DirectX


%(dulo 1 ? Cap!tulo B
A. "ibuando l!neas con 5"-D
Lo primero que aprenderemos a representar con GDI+ y Visual Basic 2005, son lneas
muy sencillas.
'!neas simples
187
Cuando representamos lneas, debemos tener en cuenta varios aspecto, similares por
otra parte, a Visual Basic 6.
Una lnea est representada por dos puntos. Cuando la representamos en un plano, La
representacin de una lnea tiene dos pares de puntos (esto me recuerda a mis
tiempos de estudiante con el lgebra y el clculo).
Para representar una lnea por lo tanto, debemos indicar un par de puntos (x,y) cuyas
coordenadas (horizontal,vertical), representa en este orden, el lugar o punto de inicio
indicado por el margen superior del formulario o superficie sobre la cul deseamos
dibujar nuestra lnea, y un segundo par de puntos que representan la direccin final de
nuestra lnea.
Un ejemplo prctico de este tipo de representacin es la que se detalla en el siguiente
cdigo fuente de ejemplo:
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
e/;ra2hics/DraJ'ine(AeJ S-stem/DraJing/?en(Color/DarQ,l!e, 2), 1, 1,
50, 50)
n% S!b
n% Class
Atendiendo al cdigo, observamos que hemos representado la grfica indicando que
queremos dibujar una lnea e.1rap"ics.Dra!Line indicando posteriormente una serie
de atributos como el color del lpiz y tamao o grosor de ste +en/Color.Dar6Blue3 20
y un conjunto de parmetros (x,y) que representan las coordenadas de la lnea (1,1) y
(50,50).
Otra representacin similar sera e.1rap"ics.Dra!Line/+ens.Dar6Blue3 H3 H3 CB3 CB0,
con la salvedad de que en este caso, el grosor del lpiz es el grosor por defecto, que
es 1.
De todos los modos, la declaracin e.1rap"ics.Dra!Line/$e!
System.Dra!ing.+en/Color.Dar6Blue3 203 H3 H3 CB3 CB0 y e.1rap"ics.Dra!Line/$e!
System.Dra!ing.+en/Color.Dar6Blue3 203 CB3 CB3 H3 H0 en el caso de la representacin
de lneas es igualmente compatible.
Este ejemplo de prueba en ejecucin es el que se puede ver en la figura 1.
188
jemplo de dibujo con <DIB de una l@nea recta en un formulario 6indo7s
Figura 1


'!neas personali*adas
Sin embargo, la representacin de lneas con GDI+ tiene diferentes particularidades
que nos permiten sacar un alto grado de personalizacin a la hora de pintar o
representar las imgenes y grficos en nuestras aplicaciones.
La representacin de lneas con GDI+, nos permite entre otras cosas, personalizar no
slo el color y el grosor de una lnea, sino otras caractersticas de sta como por
ejemplo los extremos a dibujar.
As, podemos dibujar unos extremos ms o menos redondeados, puntiagudos, o
personalizados.
Esto lo conseguimos hacer mediante las propiedades .tart"ap y %nd"ap de la clase
-en que es lo que vulgarmente he denominado como lpiz.
A estas propiedades, las podemos dar diferentes valores. Sirva el siguiente ejemplo de
muestra de lo que podemos llegar a hacer.
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
Dim 'a2i& As AeJ ?en(Color/DarQ,l!e, 10)
'a2i&/StartCa2 = DraJing2D/'ineCa2/Diamon%Anchor
'a2i&/n%Ca2 = DraJing2D/'ineCa2/ArroJAnchor
e/;ra2hics/DraJ'ine('a2i&, 10, 10, 1.0, 1.0)
n% S!b
189
n% Class
Demostracin de como representar diferentes e5tremos en una l@nea con <DIB
Figura 2


Tra*ando caminos o rutas de l!neas
Otra posibilidad de GDI+ es la de crear lneas entrelazadas sin llegar a cerrarlas.
Esto se hace con el mtodo Add9ine.
De esta manera, podemos dibujar diferentes lneas para representarlas en el marco de
trabajo.
El siguiente ejemplo, nos ensea a utilizar el mtodo Add9ine.
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
Dim "!ta As AeJ DraJing2D/;ra2hics?ath()
"!ta/Start)ig!re()
"!ta/A%%'ine(AeJ ?oint)(10, 10), AeJ ?oint)(100, 10))
"!ta/A%%'ine(AeJ ?oint)(10, 10), AeJ ?oint)(1N0, 100))
"!ta/A%%'ine(AeJ ?oint)(1N0, 100), AeJ ?oint)(130, 50))
Dim 'a2i& As AeJ ?en(Color/DarQ,l!e, .)
e/;ra2hics/DraJ?ath('a2i&, "!ta)
190
n% S!b
n% Class
En la figura 3 podemos ver el resultado de crear diferentes lneas en Visual Basic 2005
con GDI+.
jecucin del ejemplo de uso del mtodo AddLine con &isual #asic ,++-
Figura 3
Observando el cdigo, vemos que hemos declarado el mtodo .tart:i'ure y el
mtodo Add9ine de la clase 0rap,ics-at,.
Finalmente y para representar la grfica correspondiente, hemos llamado al mtodo
Draw-at,.


'!neas con te;turas
Otra de las caractersticas de la representacin grfica de lneas con Visual Basic 2005
y GDI+, es la posibilidad de representar lneas aplicando a esas lneas una
determinada textura.
El siguiente ejemplo, aplica una textura de la bandera de la Comunidad Econmica
Europea a un camino de lneas.
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
Dim Imagen As AeJ ,itma2("cDU)lag/bm2")
Dim Ce2illo As AeJ 1eGt!re,r!sh(Imagen)
191
Dim 1eGt!ra?incel As AeJ ?en(Ce2illo, 20)
Dim "!ta As AeJ DraJing2D/;ra2hics?ath()
"!ta/Start)ig!re()
"!ta/A%%'ine(AeJ ?oint)(10, 10), AeJ ?oint)(1X0, 50))
"!ta/A%%'ine(AeJ ?oint)(10, 100), AeJ ?oint)(1X0, 1.0))
e/;ra2hics/DraJ?ath(1eGt!ra?incel, "!ta)
n% S!b
n% Class
Como podemos observar, lo primero que hacemos es cargar una imagen que ser la
textura que utilizaremos, dentro de un objeto it)ap, para posteriormente, preparar
el trazo con su textura y tamao.
Luego creamos una ruta o camino que marcaremos para dibujarla en el formulario
Windows en nuestro caso, tal y como puede verse en la figura 4.
jemplo de un tra4o de l@nea aplicando te5turas
Figura 4

192

%(dulo 1 ? Cap!tulo B
B. "ibuando curvas con 5"-D
La representacin de curvas con GDI+ tiene cierta similitud con la representacin de
lneas.
A continuacin veremos las partes ms destacables en la creacin de trazos curvos
con Visual Basic 2005 y GDI+.


Tra*ando curvas simples
Lo ms sencillo de todo es siempre el trazo de una lnea curva genrica con Visual
Basic 2005.
Esto lo conseguiremos con el siguiente cdigo:
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
Dim ?!ntos As ?oint)() = =AeJ ?oint)(10, Hath/Sin(1) O 100), +
193
AeJ ?oint)(60, Hath/Sin(0) O 100), +
AeJ ?oint)(110, Hath/Sin(1) O 100), +
AeJ ?oint)(160, Hath/Sin(0) O 100), +
AeJ ?oint)(210, Hath/Sin(1) O 100)>
e/;ra2hics/DraJC!r5e(AeJ ?en(Color/DarQ0range, .), ?!ntos, 2/0))
n% S!b
n% Class
Si observamos este cdigo, veremos que lo que hacemos es crear un conjunto de
puntos para representar los trazos o lneas rectar que unan los puntos. Esto lo
conseguimos utilizando la clase -oint:.
Posteriormente utilizamos el mtodo Draw"ur$e con la salvedad de que el tercer
parmetro, indica la tensin de la curva.
Si este valor recibe un B.B), la curva no tendr tensin y por lo tanto, la
representacin ser en trazos rectos, mientras que si ese valor aumenta, la tensin
aumenta producindose el efecto curvo que deseamos conseguir.
El ejemplo anterior en ejecucin es el que se muestra en la figura 1
jemplo en ejecucin de la representacin "r>fica de tra4os curvos
Figura 1


Curvas de .0*ier
Otra posibilidad que nos ofrece GDI+ es la representacin de curvas de Bzier, algo
que conseguiremos gracias al mtodo Drawe;ier de GDI+.
La representacin de las curvas de Bzier pueden hacerse mediante dos pares de
puntos (x,y) o mediante cuatro coordenadas de puntos que definen la asignacin de
las curvas a representar.
El siguiente ejemplo nos muestra como representar una curva de Bzier con Visual
Basic 2005 y GDI+.
194
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
e/;ra2hics/DraJ,e&ier(AeJ ?en(Color/DarQ,l!e, 3), +
AeJ ?oint)(10, 10), +
AeJ ?oint)(110, N0), +
AeJ ?oint)(160, 30), +
AeJ ?oint)(210, 110))
n% S!b
n% Class
Este cdigo en ejecucin es el que puede verse en la figura 2.
3epresentacin de las curvas de #4ier con <DIB en &isual #asic ,++-
Figura 2


Eellenando curvas
En algunas ocasiones, nos podemos ver con la necesidad de crear curvas y de rellenar
su interior para destacarlo de alguna manera. Esto es lo que veremos a continuacin.
195
El mtodo AddArc nos permite aadir una serie de puntos para representar una
circunferencia.
En realidad, se representan puntos, los cuales son el punto (x,y) inicial, el ancho y el
alto de la representacin, el ngulo de comienzo de representacin, y el ngulo final
de la representacin.
En ejemplo que veremos a continuacin, utilizaremos tambin los mtodos :ill-at, y
Draw-at,, para representar la curva en el formulario.
El cdigo del ejemplo es el que se detalla a continuacin:
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
He/,acQColor = Color/'ight,l!e
Dim Camino As AeJ DraJing2D/;ra2hics?ath()
Camino/A%%Arc(50, 0, 150, 150, 0, 1X0)
e/;ra2hics/)ill?ath(,r!shes/<hite, Camino)
e/;ra2hics/DraJ?ath(?ens/,lacQ, Camino)
n% S!b
n% Class
En la figura 3, podemos ver el ejemplo en ejecucin.
jemplo de un dibujo de curvas cerradas rellenando su interior
196
Figura 3


"ibuando tartas
Otra posibilidad que nos ofrece GDI+ es la representacin de las conocidas tartas.
Todas estas representaciones son representaciones 2D, pero siempre se puede emular
una representacin 3D, superponiendo tartas una encima de otra.
El siguiente ejemplo, utiliza los mtodos :ill-ie y Draw-ie para generar un grfico de
tarta y rellenarlo de un determinado color.
El cdigo de nuestro ejemplo, quedara de la siguiente manera:
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
e/;ra2hics/)ill?ie(,r!shes/'ight,l!e, 50, 20, 120/0), 120/0), 115/0),
1X0/0))
e/;ra2hics/DraJ?ie(?ens/DarQ,l!e, 50, 20, 120/0), 120/0), 115/0),
1X0/0))
e/;ra2hics/)ill?ie(,r!shes/<hite, 50, 20, 120/0), 120/0), 0/0),
115/0))
e/;ra2hics/DraJ?ie(?ens/DarQ0range, 50, 20, 120/0), 120/0), 0/0),
115/0))
n% S!b
n% Class
Nuestro ejemplo en ejecucin, es el que se muesta en la figura 4.
197
Demostracin de cmo crear "r>ficos de tartas y como rellenar su interior
Figura 4
-onse(o3
Cuando represente gr@ficas de tartas por ejemplo y desee rellenar una
parte de esta de un color y marcar el borde en otro color3 use primero
el m:todo )ill+ie y despu:s el m:todo Dra!+ie3 en caso contrario3 la
representaci<n gr@fica perder@ nitide. como se indica en la siguiente
imagen=
198

%(dulo 1 ? Cap!tulo B
3. "ibuando cadenas de te;to con 5"-D
Como hemos visto ya en el captulo referente a la creacin de nuestros propios
controles, desde Visual Basic 2005, podemos utilizar GDI+ para crear cadenas de
texto y manipularlas como deseemos.
En los siguientes apartados veremos como representar cadenas de texto desde Visual
Basic 2005


"ibuando cadenas de te;to
El mtodo Draw.trin' nos permite representar cadenas de texto de forma grfica.
El funcionamiento en Visual Basic 2005 de estas instrucciones es realmente simple.
El siguiente ejemplo, ilustra en cmo abordar un pequeo proyecto para representar
una cadena de texto en pantalla.
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
199
Dim Hi)!ente As AeJ )ont("$er%ana", 2., )ontSt-le/,ol%)
Dim ,rocha As AeJ Soli%,r!sh(Color/,!rl-<oo%)
e/;ra2hics/DraJString("#em2lo ;DIB", Hi)!ente, ,rocha, 10, 10)
n% S!b
n% Class
Este ejemplo en ejecucin es el que puede verse en la figura 1.
jemplo de cmo insertar una cadena de te5to "r>ficamente en un formulario
Figura 1


"ibuando cadenas de te;to con te;tura
Otra particularidad que a estas alturas ya no lo es tanto, es la posibilidad de trabajar
con texturas dentro de cadenas de texto.
Como si estuviramos dibujando una cadena de texto, la nica variacin es que
asignamos como brocha de dibujo, una textura determinada.
El siguiente cdigo, aclarar suficientemente esto que comento.
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
200
Dim Imagen As AeJ ,itma2("cDU)lag/bm2")
Dim 1eGt!raDe)on%o As AeJ 1eGt!re,r!sh(Imagen)
Dim Hi)!ente As AeJ )ont("Arial", 30, )ontSt-le/,ol%)
e/;ra2hics/DraJString("#em2lo ;DIB", Hi)!ente, 1eGt!raDe)on%o, .,
10)
n% S!b
n% Class
El resultado de este ejemplo, es el que puede verse en la figura 2.
Demostracin del efecto de a2adir una te5tura a la representacin de una cadena de te5to
Figura 2

201
%(dulo 1 ? Cap!tulo B
C. $tras consideraciones
:so de degradados con 5"-D
GDI+ proporciona un variadsimo juego de brochas que nos permiten dibujar
degradados en un formulario o control que permita el trabajo con grficos.
El siguiente ejemplo de cdigo, nos muestra como dibujar un degradado en un
formulario Windows.
Im2orts S-stem/DraJing
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
Dim )orma As AeJ "ectangle(AeJ ?oint(0, 0), He/ClientSi&e)
Dim ;ra%iente As AeJ DraJing2D/'inear;ra%ient,r!sh()orma, +
Color/C-an, +
Color/DarQ,l!e, +
DraJing2D/'inear;ra%ientHo%e/)orJar%Diagonal)
e/;ra2hics/)ill"egion(;ra%iente, AeJ "egion()orma))
n% S!b
n% Class
La figura 1 representa el ejemplo anterior en ejecucin
202
3epresentacin "r>fica de un de"radado en una ventana 6indo7s
Figura 1
Evidentemente, podemos jugar con la clase 9inear0radientrus, y con la lista
enumerada 9inear0radient<ode para dar una aspecto o un toque ligeramente
diferente al degradado, como el que se indica en la figura 2.
:tro ejemplo de representacin de"radada en un formulario 6indo7s
Figura 2


-nsertando y trabaando con im&genes con System."raFing
Sirva como detalle general, que GDI+ nos permite tambin, trabajar con imgenes.
Para cargar una imagen en un formulario con GDI+, utilizaremos el mtodo
DrawI)a'e.
Un ejemplo del uso de este mtodo para cargar una imagen en un formulario es el
siguiente:
Im2orts S-stem/DraJing
203
?!blic Class )orm1
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
e/;ra2hics/DraJImage(AeJ ,itma2("cDU15E/#2g"), 1, 1)
n% S!b
n% Class
La figura 3 nos muestra el resultado final de insertar una imagen en el formulario
Windows.
Ima"en insertada con <DIB dentro del formulario 6indo7s
Figura 3


Aplicando transparencias a una imagen
Otra de las caractersticas que nos ofrece GDI+, es el trabajo con imgenes aplicando
transparencias.
Para realizar esto, deberemos indicar el color o colores que queremos utilizar para
provocar en l un efecto transparente.
El siguiente ejemplo, nos muestra como hacer esto utilizando para ello el mtodo
<a=e4ransparent.
Im2orts S-stem/DraJing
?!blic Class )orm1
204
?rotecte% 05erri%es S!b 0n?aint(,-$al e As
S-stem/<in%oJs/)orms/?aint5entArgs)
H-,ase/0n?aint(e)
Dim Imagen As AeJ ,itma2("cDU)lag/bm2")
e/;ra2hics/DraJImage(AeJ ,itma2(Imagen), 1, 1)
Imagen/HaQe1rans2arent(Color/)romArgb(255, 0, 51, 153))
e/;ra2hics/DraJImage(AeJ ,itma2(Imagen), 100, 1)
n% S!b
n% Class
Ima"en insertada con <DIB dentro del formulario 6indo7s
Figura 4
205

-ntroducci(n
En este captulo, aprenderemos lo que son los ensamblados o assemblies, un trmino
completamente nuevo para los desarrolladores de Visual Basic 6, y aprenderemos a
desplegar o instalar nuestras aplicaciones.
Siempre que terminamos de desarrollar un proyecto, nos aborda la duda y pregunta
casi obligada de Ny a"ora 9u:O.
Eso es lo que veremos en este captulo... el 9u:.
%(dulo 1 ? Cap!tulo 3

1. Desmitificando los ensamblados
2. Desplegando con XCOPY
3. GAC y Strong Names
4. Creando un paquete de instalacin
5. Otras consideraciones

206

%(dulo 1 ? Cap!tulo 3
@. "esmitificando los ensamblados
Un concepto completamente nuevo para un desarrollador de Visual Basic 6, es la
palabra Asse)!l5, denominada ensamblado.
Los ensamblados, son para entenderlo muy rpidamente, como los ejecutables de una
aplicacin.
La nica diferencia notable, es que en .NET, un proyecto o aplicacin, se compila en
cdigo intermedio, el conocido como Intermediate Language o lenguaje intermedio,
que luego interpretar el CLR o Common Language 'untime para ejecutarla en el
sistema operativo correspondiente.
Ese cdigo intermedio, es el ensamblado de nuestra aplicacin que a su vez puede
contener uno o ms ficheros, y a su vez, un proyecto, puede estar contenido por uno o
ms ensamblados.
Por lo tanto, dentro de un ensamblado, se encierran algunas partes importantes que
debemos conocer.
Lo mejor para entender bien lo que hay en un ensamblado y que contiene es que
abramos Visual Basic 2005 Express y seleccionemos una plantilla de proyecto de tipo
"onsole Application como se muestra en la figura 1.
207
!eleccionando un proyecto de tipo Console Application
Figura 1
A continuacin, escribiremos un ejemplo simple de consola, para que estudiemos el
resultado de ste.
El cdigo fuente de nuestra pequea aplicacin de ejemplo, es el que se detalla a
continuacin:
Ho%!le Ho%!le1
S!b Hain()
Console/<rite'ine("#em2lo %e consola")
Console/<rite'ine("")
Console/<rite("(?!lse nter 2ara terminar*")
Console/"ea%'ine()
n% S!b
208
n% Ho%!le
Nuestro ejemplo de prueba en ejecucin, es el que puede verse en la figura 2.
jecucin del ejemplo de Consola
Figura 2
Ahora bien, lo que tenemos una vez compilamos nuestra aplicacin de consola, no es
un ejecutable como tal o como lo entendramos en Visual Basic 6.
En Visual Basic 6, generbamos un ejecutable nativo al sistema en el cul
compilbamos el proyecto y si ese ejecutable lo llevbamos a otra mquina con otro
sistema operativo diferente a Windows, ese programa no iba a funcionar.
Con .NET y en nuestro caso con Visual Basic 2005, este concepto ha cambiado.
El proyecto que hemos desarrollado no se compila a un ejecutable nativo, sino que el
sistema .NET lo compila a un lenguaje intermedio, que luego el "93 de la mquina en
la cul lanzamos nuestra aplicacin, ser capaz de interpretar adecuadamente.
Puede que estos conceptos le puedan desorientar un poco, pero es muy fcil de
comprender.
Adicionalmente a sto, lo suyo es destripar un poco lo que hay dentro del ensamblado
que hemos convertido a cdigo intermedio.
Para llevar a cabo nuestra tarea, haremos uso de una herramienta externa de
Microsoft y del entorno Visual Basic 2005 Express, que nos permite analizar el
ensamblado de un proyecto convertido a cdigo intermedio.
4claracin3
,n ensamblado o el c<digo intermedio3 /I9 a partir de a"ora03 no es ni
el c<digo fuente de nuestra aplicaci<n ni el programa ejecutable.
%l I9 se puede anali.ar con una "erramienta de (icrosoft denominada
ildas).
209
Cuando abrimos el fichero ejecutable de nuestra aplicacin con la herramienta
ildasm.e&e, observamos que esta tiene una gran cantidad de informacin, como se
indica en la figura 3.
ildasm con el fic%ero ejecutable de nuestra aplicacin de ejemplo abierto
Figura 3
Antes de adentrarnos ms en los entresijos de un ensamblado, piense en l como si
fuera una coleccin de elementos.
Esos elementos, pueden ser recursos, tipos, funcionalidades, que todas juntas, forman
nuestra aplicacin.
As, lo primero que vemos en la figura 3, es la palabra M4NIFIEST.
Referencias a las libreras utilizadas que el -*B deber interpretar posteriormente.
Luego encontramos otras el mbito de la aplicacin y las clases de sta, con sus
mtodo tanto estticos como no estticos.
210
No es cuestin de entrar mucho ms en detalle del cdigo I* que contiene un proyecto
compilado en .NET como ste, pero es conveniente a verlo para entender los
conceptos que estamos tratando.
Los ensamblados como podemos ver, contiene ms informacin de la que propiamente
tendra un ejecutable normal como lo conocemos los desarrolladores de Visual Basic 6.
Un ensamblado en .NET, contiene tambin como hemos podido ver, datos e
informacin que encontraramos en cualquier tipo de librera, lo cul representa
adems, toda la informacin necesaria del -*B en cualquier momento.
Con todo esto, podemos resumir por lo tanto, que un ensamblado contiene cdigo,
recursos y metadatos.
El cdigo en I* es el cdigo que ser ejecutado por el -*B.
Adems, cualquier recurso (imgenes, metadatos, etc) son accesibles en el
ensamblado.
Los metadatos por su parte, contiene informacin sobre las clases, interfases, mtodos
y propiedades, que posibilitan toda la informacin necesaria por el -*B para poder
ejecutar nuestra aplicacin correctamente.


%(dulo 1 ? Cap!tulo 3
1. "esplegando con GC$,H
Notas previas
Todas las aplicaciones desarrolladas con .NET estn aisladas, no como ocurra en
Visual Basic 6, de manera tal que los conflictos con las DLL se han visto reducidos
enormemente, por no decir que han desaparecido.
El famoso infierno de las DLLs que tanto hemos sufrido los desarrolladores de Visual
Basic, ha pasado ya a la historia.
211
Al igual que en Visual Basic, puedes usar componentes privados.
Basta con copiarlos al mismo directorio en el que se encuentra nuestra aplicacin
ejecutable.
Adems, .NET nos permite tener ms de un componente versionado (diferentes
versiones de un mismo componentes) dentro de un mismo ordenador, por lo que los
problemas de compatibilidad estaran resueltos.
Con estos detalles, repasamos algunas de las mejoras a la hora de desplegar o instalar
una aplicacin desarrollada con Visual Basic 2005 en un sistema.
A continuacin, veremos algunas anotaciones adicionales que nos ayudarn a realizar
estas y otras acciones.


GC$,H
Lo que nos ofrece L-78S a los desarrolladores e ingenieros, es la posibilidad de
instalar e implementar nuestra solucin y proyecto a un sistema de una manera
rpida, fiable y sin apenas impacto.
El mtodo L-78S para desplegar aplicaciones, pasa por alto la posibilidad de
implementar los ensamblados en la O4-, algo que segn determinadas circunstancias,
resulta ms que provechoso.
Hay que tener en cuenta, que si hacemos un mal uso de la O4-, sta puede
convertirse en un desvn difcil de gestionar.
Utilice la O4- con criterio y si no quiere complicaciones, despliegue sus aplicaciones
con L-78S.
Como habr podido ya observar, dentro de un proyecto de Visual Basic 2005, nos
podemos encontrar con una extensa estructura de directorios.
Esta estructura, lejos de ser una molestia, constituye las caractersticas ms
importantes a la hora de desplegar nuestras aplicaciones a travs de L-78S.
Como vemos, todo en .NET tiene su sentido y tiene un porqu.
Para instalar nuestra aplicacin desarrollada en Visual Basic 2005 en un sistema
cliente, bastar por lo tanto, con realizar una accin similar al L-78S de DOS, es
decir, copiaremos en el ordenador cliente, los ficheros o ensamblados necesarios
(ejecutables, recursos, dlls, etc.) de la estructura de nuestro proyecto.
Debemos tener en cuenta, que en Visual Basic 6, podamos hacer esto igualmente,
pero debamos adems registrar las DLL con aquel famossimo comando regsr32 para
que no hubiera problemas, an as, algunas veces nos encontrbamos con algunos
contratiempos, sin embargo, con Visual Basic 2005, esta forma de trabajar ha
desaparecido y ahora el despliegue de una aplicacin es mucho ms sencilla.
J7(oK
Cuando desarrollemos una aplicaci<n3 tenga en cuenta otros recursos
9ue utili.a en la misma.
Crystal 'eports3 bases de datos SEL Serer3 9ue la m@9uina cliente
disponga de .$%T )rame!or6 o de la ersi<n mInima de (D*C
necesaria3 etc.
%n caso contrario3 la ejecuci<n de nuestra aplicaci<n3 podrIa no
funcionar o proocar alg;n tipo de e&cepci<n o error.
+or ;ltimo3 y aun9ue pare.ca de perogrullo3 no olide 9ue debe tener
los permisos necesarios para instalar y ejecutar los ensamblados y
otras partes de Soft!are3 necesarios para ejecutar su aplicaci<n.
212


%(dulo 1 ? Cap!tulo 3
A. 5AC y Strong Names
5AC
El O4- o 1lobal *ssembly Cac"e no es otra cosa que un repositorio de ensamblados
globales.
Imaginemos que ustes todos los das cuando llega a casa de trabajar, lo primero que
hace es quitarse los zapatos y ponerse una zapatillas cmodas para estar por casa.
Lo lgico en este caso, ser situar un zapatero o un pequeo armarito para que ponga
ah las zapatillas, ya que todos los das, hace repetitivamente esta operacin.
Obviamente, las zapatillas deben de estar ah y no en la otra punta de la casa, pero
para estar en ese zapatero, deber cumplir una serie de requisitos que usted mismo
exige, por lo que no todos los zapatos o zapatillas deberan estar ah.
El O4- funciona de una manera realmente semejante.
En el O4- se incluyen aquellas libreras o ensamblados que son utilizados
frecuentemente.
Si usted va a desarrollar y distribuir su propio ensamblado, convendra ponerlo en el
O4-.
Una aplicacin .NET, lo primero que hace cuando se ejecuta, es revisar los
ensamblados que va a necesitar, y el primer sitio dnde va a ir a buscarlo es en el
O4-.
Sino lo encuentra, se pondr a buscarlo en el directorio en el que se encuentra el
fichero ejecutable, pero esto repercute en el rendimiento.
Si nuestras aplicaciones utilizan frecuentemente unos ensamblados, sera lgico y
conveniente ponerlos en el O4-.
213
Y cmo se aade un ensamblado al O4-?.
La tarea no es sencilla, ya que para aadirlo debemos realizar algunos pasos, entre los
que est el crear un nombre fuerte o .tron' +a)e.


Strong Names
Con los Stron' Names, aseguramos un uso seguro de los componentes contenidos en
el ensamblado.
Hay que tener en cuenta que un ensamblado declarado en la O4- que es llamado por
varias aplicaciones, crea una nica instancia.
De ah, que crear un Stron' Name para el ensamblado, est ms que justificado.
Un Stron' Name, nos asegura por otro lado, que el nombre de un ensamblado es
nico y que por lo tanto, al ser nico, no puede ser utilizado por otros ensamblados.
Los Stron' Names se generan con un par de claves, una de ellas de carcter pblico
y otra de carcter privado, claves que se introducen en fichero de ensamblado de la
aplicacin, y que luego al compilar nuestra aplicacin, queda registrada con ese
Stron' Name.
Para indicar un Stron' Names a un ensamblado, debe crear primero el par de claves
(clave pblica y clave privada), que se generar en un fichero con extensin sn!, y
modificar posteriormente el fichero *ssemblyInfo.b de su proyecto.
En ese archivo, debe aadir una instruccin similar a la siguiente:
<Assembly: AssemblyKeyFile("KeyFile.snk")>


214
%(dulo 1 ? Cap!tulo 3
B. Creando un pa6uete de instalaci(n
Setup ,roect
Otra accin habitual, es que cuando desarrollemos nuestras aplicaciones, generemos
diferentes dependencias con otros ensamblados o componentes, para lo cul, la forma
ms sencilla de desplegar nuestra aplicacin, es generando un paquete de distribucin
que contenga esas dependencias y relaciones.
En el caso de Visual Basic 2005 Express, esta opcin no est disponible, aunque s en
versiones ms avanzadas de Visual Studio 2005.
Con la plantilla Setup +roject que no viene integrada en Visual Basic 2005 Express,
crearemos un nuevo proyecto para generar el paquete de distribucin e instalacin de
nuestra aplicacin y proyecto.
Cuando generamos el paquete de instalacin, debemos tener en cuenta que se
generan dos archivos que por lo general tendrn los nombres de Setup.e&e y
Setup.msi.
La diferencia entre ambos ficheros es que el fichero con extensin e;e instalar
4indo!s Installer si es necesario, mientras que el fichero con extensin msi, no
instalar 4indo!s Installer, por lo que si 4indo!s Installer no est presente en la
mquina en la que se ejecuta el programa de instalacin, dar un error.
Otra consideracin a tener en cuenta cuando generamos el paquete de instalacin, es
en el momento de la distribucin, el asegurar que el sistema destino tenga el .NET
Framework correspondiente.
Su'erencia3
Cmo usar Visual Studio 2005 para distribuir Microsoft .NET
Framework?
(@s 9ue interesante artIculo d<nde obtendr@ informaci<n adicional
sobre c<mo generar un pa9uete de instalaci<n para distribuir .$%T
)rame!or6.
Using Visual Studio .NET to Redistribute the .NET Framework (en ingls)
Respecto al comportamiento de 4indo!s Installer sobre aplicaciones ya instaladas que
deseamos desinstalar, el entorno se comporta de manera tal, que si detecta
componentes compartidos, estos no son desinstalados del sistema.
Otro comportamiento de 4indo!s Installer es el que nos permite echar marcha atrs
si el proceso de instalacin se cancela o falla por algn motivo.
4indo!s Installer dejar el sistema en el mismo estado que tena justo antes de
realizar la instalacin.


Tipos de despliegues de proyectos
Cuando generamos un paquete de instalacin tenemos dentro del entorno de
desarrollo Visual Studio varias opciones, como se indica en la imagen 1.
As, nos podemos encontrar por lo general con diferentes tipos de despliegues de
proyectos.
215
$ipos de desplie"ue de proyectos en &isual !tudio Cno en &isual #asic ,++- 5pressD
Figura 1
La plantilla "a! -roject El fichero con extensin -4B es un fichero comprimido que
contiene todos los ficheros y recursos necesarios para instalar nuestra aplicacin.
Por lo general, este tipo de ficheros son usados para descargarlos de Servidores Web.
Por lo general y en nuestro caso, crearemos aplicaciones Windows, y deberamos
entonces utilizar la plantilla Setup 8ro(ect.
Si utilizamos la plantilla, <er'e <odule -roject, crearemos un paquete instalacin
para componentes compartidos.
El uso de la plantilla, We! .etup -roject por su parte, nos permitir generar un
paquete de instalacin para aplicaciones basadas en Internet o aplicaciones Web.
La plantilla, .etup Wi;ard genera un asistente para generar uno de los cuatro
anteriores tipos de proyectos de despliegue.
Es una forma rpida de generar el proyecto de despliegue.

216

%(dulo 1 ? Cap!tulo 3
3. $tras consideraciones
Setup ,roect
Ya lo hemos comentado por encima en los captulos anteriores sobre el Despliegue de
aplicaciones, pero cuando se procede a instalar y distribuir una aplicacin en otros
sistemas, se deben tener en cuenta diferentes aspectos que no podemos pasar por
alto.
Debemos conocer en primer lugar, la naturaleza del sistema o sistemas destino dnde
vamos a implantar nuestro programa.
Entendiendo y conociendo bien esto, podremos saber qu aplicaciones Software
adicionales necesitaremos para abordar nuestro trabajo adecuadamente.
Entre otros, debemos tener en cuenta que el sistema destino dnde se va a ejecutar
nuestra aplicacin dispone de los drivers de acceso a datos adecuados, (D*C (versin
2.6 superior), y por supuesto de Microsoft .NET Framework.
F4N3
Cuando instalar con Windows Installer y cuando a travs de XCOPY?
Interesante artIculo 9ue debate sobre cuando instalar con 4indo!s
Installer y cuando con JCO+P.
Determining When to Use Windows Installer Versus XCOPY (en ingls)
El anterior artculo, nos da un enfoque sobre qu tipo de instalacin o despliegue
establecer de nuestra aplicacin desarrollada con Visual Basic 2005.


El concepto ClicI$nce
En #isual Basic 2BBC %&press se instroduce un concepto nuevo denominado Clic6Once.
217
Este concepto representa la tecnologa que permite instalar y ejecutar aplicaciones
Windows desde un servidor Web con una escasa accin por parte del usuario.
Inicie un nuevo proyecto Windows. Dentro del formulario Windows inserte un control
Button dentro del cul, inserte un texto identificativo como el que se muestra en la
figura 1.
Aplicacin 6indo7s de ejemplo para e5plicar el concepto de Clic=:nce
Figura 1
A continuacin, escriba el siguiente cdigo fuente:
?!blic Class )orm1
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
Hessage,oG/ShoJ("#em2lo ClicQ0nce e#ec!ta%o a lasD" P 5bCr'8 P
Date/AoJ/1o'ong1imeString)
n% S!b
n% Class
Una vez que ha escrito el cdigo fuente de la aplicacin, ejectela y compruebe que
funciona como se espera.
Si lo desea, abra el fichero *ssemblyInfo.b e indique la versin de la aplicacin que
desee. En mi caso he dejado la versin H.B.B.B que es la versin que aparece por
defecto.
218
Despus de esto, genere la aplicacin como se indica en la figura 2.
<eneramos la aplicacin para comprobar entre otras cosas que todo est> preparado
Figura 2
Por ltimo, pulse el botn derecho del ratn sobre el proyecto y seleccione la opcin
8u#licar... como se indica en la figura 3.
:pcin de 9ublicar la aplicacin para ejecutar la tecnolo"@a de distribucin Clic=:nce
Figura 3
Al ejecutar la opcin 8u#licar..., el entorno nos muestra una ventana similar a la que
se muestra en la figura 4.
219
Asistente de la publicacin de la aplicacin
Figura 4
Seleccione una ubicacin para publicar la aplicacin y haga clic en el botn Si'uiente.
Aparecer en el asistente entonces, una ventana similar a la que se presenta en la
figura 5.
220
&entana del asistente para indicar dnde estar> disponible la aplicacin
Figura 5
Pulse el botn Si'uiente.
Nuevamente, el asistente mostrar una ltima ventana similar a la que se muestra en
la figura 6.
221
&entana final del asistente con un resumen de las opciones seleccionadas
Figura 6
El asistente muestra en este caso, una informacin de resumen. Lo que haremos a
continuacin, ser pulsar el botn Finali@ar.
Con esta accin, nuestra aplicacin est ya publicada en el servidor web, por lo que si
abrimos una ventana de nuestro explorador Web y escribimos la direccin en la cul
hemos publicado nuestra aplicacin, sta se ejecutar de forma correcta como se
indica en la figura 7.
222
Aplicacin 6eb del lan4amiento de la aplicacin 6indo7s a travs del !ervidor 6eb
Figura 7
Si pulsamos sobre el botn E(ecutar del navegador web, observaremos que el
Servidor Web realiza diferentes acciones de verificacin. La primera accin es una
accin de conexin como la que se muestra en la figura 8.
La primera accin que se reali4a es una accin de cone5in con el !ervidor 6eb
Figura 8
Posteriormente, puede aparecer una ventana de seguridad como la que se indica en la
figura 9, siempre y cuando no hayamos realizado un proceso de generacin segura o
confiable de la aplicacin, como ha sido el caso.
223
La aplicacin 6indo7s ejecutada a travs del !ervidor 6eb8 debe ser confiable y se"ura
Figura 9
En nuestro caso, como sabemos que no hay problema en ejecutar la aplicacin,
pulsaremos el botn E(ecutar.
Nuestra aplicacin en ejecucin es la que se muestra en la figura 10.
Aplicacin 6indo7s en ejecucin
Figura 10
Cuando hacemos esto, siempre que ejecutemos la aplicacin, el sistema detectar que
aceptamos una vez su seguridad, por lo que siempre se ejecutar sin indicarnos
ningn mensaje de seguridad.
Ahora bien, supongamos que decidimos modificar parte del cdigo de nuestra
aplicacin y que por supuesto, cambiamos la versin de la misma.
Acuda antes a la ventana del %&plorador de soluciones y observe que se ha aadido en
la ventana un fichero de nombre 4indo!s*pplicationH-TemporaryKey.pf& que
224
corresponde a una llave o clave temporal relacionada con el proyecto publicado. Esto
es lo que se muestra en la figura 11.
&entana del 5plorador de soluciones con el fic%ero 6indo7sApplication.E$emporaryFey*pf5 a2adido a l
Figura 11
Vamos a actualizar nuestra aplicacin y la vamos a cambiar la versin, por lo que
ahora escribiremos el siguiente cdigo:
?!blic Class )orm1
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
Hessage,oG/ShoJ("#em2lo ClicQ0nce e#ec!ta%o a lasD" P 5bCr'8 P +
Date/AoJ/1oShortDateString P 5bCr'8 P +
Date/AoJ/1o'ong1imeString)
n% S!b
n% Class
La versin de la aplicacin, la he modificado en mi caso a H.H.B.B.
El siguiente paso que he hecho es compilar la aplicacin y publicarla nuevamente.
Una vez hecho esto, acudimos a la pgina web de la aplicacin y pulsamos
nuevamente el botn E(ecutar como se indica en la figura 12.
225
&entana 6eb para ejecutar la aplicacin
Figura 12
La ejecucin de la aplicacin se realizar sin problemas de manera sencilla y
controlada.
Como vemos, la publicacin de aplicaciones Windows a travs de un Servidor Web, lo
que se denomina tecnologa de publicacin Clic6Once, es un proceso de publicacin
rpido y sencillo, que aporta grandes ventajas y que en otras versiones de .NET trae
consigo algunos inconvenientes superados en esta versin de .NET.
-omunidad dotNet3
Si 9uiere saber m@s sobre Clic6Once3 le recomiendo la lectura del
siguiente artIculo3 escrito en espaAol 9ue complementar@ y ampliar@ la
informaci<n de este tutorial.
(Diciembre 2004) Implementacin de aplicaciones de Windows Forms con ClickOnce
226

Contenido
'ecci(n @: Colecciones de datos
o Los tipos de colecciones de .NET
o Las clases base para crear colecciones
o Colecciones de tipo generic (en breve)
'ecci(n 1: Streams en .NET
o Las clases basadas en Stream
o Manejar un fichero usando FileStream
o Manejar ficheros con StreamReader y StreamWriter
o Cifrar y descifrar un fichero
'ecci(n A: Acceso al sistema de arc#ivos
o Las clases de System.IO
o Clases para manipular unidades, directorios y ficheros
o Clases para leer o escribir en streams
o El objeto My: My.Computer.FileSystem
'ecci(n B: Acceso a -nternet
o Las clases de System.Net
o Acceder a una pgina Web
o Acceder a un servidor FTP
o Acceso rpido a la red con My.Computer.Network
227

-olecciones de datos
A diferencia de Visual Basic 6.0, en la que solo tenemos dos formas de crear
colecciones, en la versin 2005 de Visual Basic, tenemos un amplio abanico de tipos
de colecciones, desde colecciones genricas (o de uso comn, para no confundir el
trmino con las colecciones "generic"), hasta colecciones especializadas, es decir,
colecciones que estn pensadas para usarlas de forma muy concreta y que por
tanto no nos sirven para usarlas en la mayora de las ocasiones.
Empecemos viendo los tres tipos bsicos de colecciones que podemos utilizar en
nuestras aplicaciones de .NET.

Nota3
Las colecciones que vamos a ver a continuacin son las colecciones
"clsicas" de .NET, (cuyo tipo interno es Object), pero debemos saber
que tambin existen colecciones casi con las mismas caractersticas
pero que estn definidas en el espacio de nombres
System.Collections.Generic, las cuales utilizan la nueva "tecnologa" de
los tipos genricos (generic) para almacenar los elementos, (cuyo tipo
interno puede ser de cualquier tipo).


228
*os tipos de colecciones de .NET
En .NET Framework existen tres tipos principales de colecciones, stas dependen del
tipo de interfaz que implementan:
Las colecciones basadas en ICollection
Las colecciones basadas en la interfaz IList
Las colecciones basadas en la interfaz IDictionary
Como podemos imaginar, dependiendo del "contrato" firmado por cada una de estos
tipos de colecciones, podremos hacer ciertas operaciones con ellas.
A continuacin veremos con ms detalle estos tipos de colecciones y cuales son las
que podemos usar dependiendo del interfaz que cada una de ellas implemente.

Nota3
La diferencia bsica entre estos tipos de colecciones es cmo estn
almacenados los elementos que contienen, por ejemplo, las
colecciones de tipo IList (y las directamente derivadas de ICollection)
solo almacenan un valor, mientras que las colecciones de tipo
IDictionary guardan un valor y una clave relacionada con dicho valor.

Tambin veremos unas clases base que implementan cada una de estas dos
interfaces, las cuales las podemos usar como base de nuestras propias colecciones
personalizadas.

'as colecciones basadas en -Collection
La interfaz ICollection es un caso aparte, ya que realmente todas las colecciones
de .NET implementan esta interfaz, de hecho, esta interfaz se deriva de
I%numerable que es la que nos permite recorrer las colecciones usando bucles )or
%ac".
Para hacer una comparacin con Visual Basic 6.0, podramos decir que las
colecciones "puramente" basadas en ICollection son las colecciones equivalentes al
tipo Collection de VB6.
Esta interfaz no la tendremos que usar de forma habitual, ya que realmente el resto
de colecciones (e interfaces) tiles ya se derivan de ella, por tanto vamos a
centrarnos en las otras dos.
Aunque es importante que tengamos en cuenta que el resto de colecciones
implementan ICollection, por tanto siempre podremos usar un objeto de este tipo
para acceder a cualquier coleccin.
229
Independientemente de que todas las colecciones de .NET estn basadas en esta
interfaz, hay ciertos tipos de colecciones que solo implementan esta interfaz, por
ejemplo las colecciones de tipo Eueue, Stac6 o Bit*rray, por tanto esas colecciones
estarn limitadas a los mtodos expuestos por la interfaz ICollection y los que esas
colecciones implementen de forma independiente.
Por regla general, los tipos que solo se basan en ICollection suelen ser colecciones
que no necesitan de las caractersticas que proporcionan las otras interfaces y, por
regla general, nos permiten la manipulacin de los datos de una forma bsica o
elemental, de forma que su uso sea para casos muy concretos.
Por ejemplo, la clase Eueue nos permite crear fcilmente una coleccin de tipo FIFO
(primero en entrar, primero en salir); por otra parte, con la clase Stac6 podemos
crear colecciones del tipo LIFO (ltimo en entrar, el primero en salir), de forma que
sean muy tiles para crear "pilas" de datos.
El caso de la otra clase que hemos comentado: Bit*rray, nos sirve para almacenar
valores de tipo "bit", en el que cada valor se almacena como un cero o un uno, de
forma que podamos tener una coleccin muy compacta, pero, tambin muy
especfica y no de uso general, ya que en este caso particular, los mtodos que
implementa esta clase estn enfocados en la manipulacin de valores de tipo
Boolean, ()alse y True), aunque internamente se almacenen como valores cero y
uno respectivamente.

Nota3
Realmente la clase BitArray no se comporta como una coleccin
"normal", ya que el tamao de la misma debemos controlarlo
nosotros, al igual que ocurre con los arrays, aunque de forma ms
"fcil", mediante la propiedad Length.


'as colecciones basadas en -'ist
La interfaz IList se utiliza en las colecciones a las que queremos acceder mediante
un ndice, por ejemplo, los arrays realmente est basados en esta interfaz, y tal
como pudimos comprobar, la nica forma que tenemos de acceder a los elementos
de un array, (y por extensin a los elementos de las colecciones basadas en IList),
es mediante un ndice numrico.
Existen tres tipos principales de colecciones que implementan esta interfaz:
Las de solo lectura, colecciones que no se pueden modificar. Este tipo de
colecciones suelen basarse en la clase abstracta 'eadOnlyCollectionBase.
Las colecciones de tamao fijo, no se pueden quitar ni aadir elementos, pero
si modificarlos. Por ejemplo, las colecciones basadas en *rray son de tamao
fijo.
230
Las de tamao variable permiten cualquier tipo de adicin, eliminacin y
modificacin. La mayora de las colecciones suelen ser de este tipo, es decir,
nos permiten dinmicamente aadir o eliminar elementos.
Existe un gran nmero de colecciones en .NET que implementan esta interfaz,
(sobre todo las colecciones basadas en controles), entre las que podemos destacar
las siguientes:
*rrayList, la coleccin "clsica" para este tipo de interfaz. Contiene todos los
miembros habituales en este tipo de colecciones.
CollectionBase, una clase abstracta para poder crear nuestras propias
colecciones basadas en IList.
StringCollection, una coleccin especializada que solo puede contener valores
de tipo cadena.

La coleccin ArrayList
Tal como hemos comentado, el tipo de coleccin que se usa como referencia a la
hora de hablar de las colecciones basadas en la interfaz IList, es *rrayList.
Esta coleccin permite aadir, eliminar y modificar fcilmente los elementos que
contiene. Tambin podemos recorrerlos mediante un bucle )or accediendo a los
elementos por medio de un ndice e incluso mediante un bucle del tipo )or %ac".
Al igual que ocurre con los arrays, el ndice inferior es siempre el cero y los
elementos se almacenan de forma consecutiva, es decir, si aadimos dos elementos
a una coleccin de tipo *rrayList (y a las que implementen la interfaz IList), el
primero ocupar la posicin cero y el segundo la posicin uno. La ventaja de
trabajar con las colecciones es que no debemos preocuparnos de reservar memoria
cada vez que vayamos a aadir un nuevo elemento, simplemente usamos el mtodo
*dd y asunto arreglado.
Lo mismo ocurre a la hora de quitar elementos de una coleccin, no tenemos que
preocuparnos demasiado por el espacio dejado al quitar elementos, de eso se
encarga el propio .NET, nosotros simplemente debemos llamar al mtodo 'emoe o
'emoe*t indicando respectivamente el elemento a eliminar o el ndice en el que se
encuentra almacenado.

Truco3
Si decidimos eliminar varios elementos de una coleccin de tipo IList
(o de un array), lo normal es que lo hagamos usando un bucle For; si
este es el caso, para evitar una posible excepcin, (realmente no es
posible, sino con toda certeza segura), debemos recorrer el bucle
desde el final hacia adelante, con idea de que al cambiar el nmero de
elementos no falle al intentar a acceder a un elemento que ya no
existe.
231


l tipo de datos de almacenamiento de las colecciones
Estos elementos internamente estn almacenados como objetos del tipo Object, por
tanto podemos aadir cualquier tipo de datos a una coleccin de este tipo, ya que
todos los tipos de datos de .NET estn basado en la clase Object.
El problema con este tipo de colecciones es que siempre que queramos acceder a
uno de los elementos que contiene, debemos hacer una conversin al tipo
adecuado, es decir, si en una coleccin de este tipo guardamos objetos de tipo
Cliente y queremos acceder a uno de ellos, debemos hacer una conversin (cast)
del tipo Object al tipo Cliente, ya que si no lo hacemos y tenemos activada Option
Strict (la opcin para las comprobaciones estrictas), se producir un error si
hacemos algo como esto:
Dim lista As AeJ Arra-'ist
lista/A%%(AeJ Cliente("?e2e"))
lista/A%%(AeJ Cliente("'ola"))
Dim !nCliente As Cliente
4 7rrorY
!nCliente = lista(0)
///
Por tanto, la ltima lnea deberamos escribirla de una de estas dos formas:
4 Fsan%o C1-2e 2ara hacer la con5ersiSn
!nCliente = C1-2e(lista(0), Cliente)
///
4 Fsan%o DirectCast 2ara hacer la con5ersiSn (m6s recomen%able)
!nCliente = DirectCast(lista(0), Cliente)

Otro de los problemas que tienen las colecciones "normales" es que en algunos
casos, particularmente cuando almacenamos tipos por valor, el rendimiento se ve
bastante mermado, ya que el runtime de .NET (el CLR) debe hacer lo que en ingls
se conoce como boxing/unboxing, es decir, convertir un tipo por valor en uno por
232
referencia cuando va a guardarlo en la coleccin (boxing), y el proceso inverso
cuando lo queremos recuperar (unboxing).
De todas formas, el consuelo que podemos tener los que estamos acostumbrados a
trabajar con Visual Basic 6.0, es que esto mismo ocurre (o casi) cuando trabajamos
con las colecciones de VB6, ya que el tipo de datos de las colecciones es #ariant,
que sera ms o menos el equivalente del tipo Object de .NET.

Nota3
Por suerte, en Visual Basic 2005 tenemos otra forma de mejorar el
rendimiento de las colecciones, y es mediante las colecciones
"generic", de esto, nos ocuparemos ms adelante.

Otras de las ventajas de las colecciones de .NET, no solo las basadas en la interfaz
IList, es que proporcionan una gran cantidad de mtodos que nos facilitan la
manipulacin de ese tipo de datos. Por ejemplo, tenemos mtodos para clasificar el
contenido de las colecciones, (aunque esos objetos deben implementar la interfaz
IComparable, tal como vimos en el ltimo ejemplo del captulo de las interfaces),
adems tienen mtodos para hacer copias, buscar elementos y muchos etcteras
ms.


'as colecciones basadas en -"ictionary
El otro grupo de colecciones que podemos encontrar en .NET son las colecciones
basadas en la interfaz IDictionary. stas, a diferencia de las colecciones IList,
siempre mantienen el par clave/valor, ya que la forma de acceder a los elementos
es mediante una clave nica. Por tanto, cada vez que aadimos un elemento a una
coleccin de este tipo tendremos que indicar una clave y un valor. Cada valor estar
relacionado con su correspondiente clave.
Sabiendo esto, es fcil adivinar que si queremos acceder a un elemento, lo normal
es que lo hagamos usando la clave indicada al aadirlo. Los que hayan trabajado
anteriormente con Visual Basic 6.0, (o lo estn haciendo actualmente), puede que
piensen que tambin se podr acceder a cada elemento mediante un ndice
numrico, ya que el objeto Collection de VB6, (que an sigue existiendo en Visual
Basic 2005), nos permite indicar una clave para cada elemento, y adems de
acceder a esos elementos mediante la clave, podemos hacerlo mediante un valor
numrico (ndice). Pero en las colecciones basadas en IDictionary, salvo casos muy
especiales, siempre accederemos a los valores contenidos mediante la clave y
"nunca" mediante un ndice que haga referencia a la posicin dentro de la coleccin,
entre otras cosas porque cuando almacenamos valores en este tipo de colecciones,
stos no se guardan en el mismo orden en que fueron aadidos.
233

Nota3
Si bien la clase Collection est disponible en la nueva versin de Visual
Basic, sta tiene algunas mejoras con respecto a la que tiene VB6,
entre esas mejoras estn dos nuevos mtodos que nos facilitarn su
uso: el mtodo Clear con el que podemos eliminar todos los elementos
de la coleccin y el mtodo Contains, con el que podemos averiguar si
un determinado elemento est en la coleccin.

Entre las colecciones basadas en la interfaz IDictionary podemos destacar:
7as"table, es la coleccin por excelencia de las basadas en IDictionary. Los
elementos se organizan basndose en el cdigo "as" de las claves.
DictionaryBase, es una clase abstracta que podemos usar como base de
nuestras propias colecciones de tipo diccionario.
ListDictionary, es una coleccin con mayor rendimiento que 7as"table
pensada para trabajar con 10 o menos elementos.
7ybridDictionary, es una coleccin especial en la que si hay 10 o menos
elementos, se utiliza una coleccin ListDictionary y si contiene ms elementos
se utiliza una coleccin 7as"table.
SortedList, es una coleccin en la que los elementos estn clasificados por las
claves. Internamente utiliza una mezcla entre 7as"table y *rray, segn la
forma en que se accedan a esos elementos.

Almacenar valores en una coleccin tipo IDictionary
Para aadir nuevos elementos a una coleccin de tipo IDictionary siempre
tendremos que indicar la clave y el valor, la clave no puede ser un valor nulo,
($ot"ing), pero puede ser de cualquier tipo. El valor tambin puede ser de cualquier
tipo y en este caso si que se admiten valores nulos.
Los elementos los aadiremos usando el mtodo *dd, al que habr que indicar
primero la clave y despus el valor:
Dim 5alores() As String = ="!no", "%os", "tres">
Dim %ic As AeJ S-stem/Collections/Hashtable
)or i As Integer = 0 1o 5alores/'ength C 1
%ic/A%%(5alores(i), "l 5alor %e " P 5alores(i))
234
AeGt


Cmo se almacenan los elementos de las colecciones IDictionary
Tal como hemos comentado, las colecciones que implementan la interfaz IDictionary
siempre almacenan un par de datos: la clave y el valor propiamente dicho, por tanto
cada vez que queramos acceder a un valor, debemos usar la clave asociada con
dicho valor. Al menos esa es la forma habitual, ya que como veremos, tambin
podremos acceder a esos valores directamente.
Debido a esta caracterstica, para acceder a los elementos de este tipo de
colecciones por medio de un bucle del tipo )or %ac", debemos usar una clase
llamada Dictionary%ntry, esta clase tiene dos propiedades, una contiene la clave y
otra el valor. Por tanto, cuando usemos un bucle )or %ac", el tipo de objeto usado
para acceder a los elementos de la coleccin ser Dictionary%ntry, tal como vemos
en el siguiente cdigo:
)or ach %e As Dictionar-ntr- In %ic
Console/<rite'ine("=0> = =1>", %e/Ze-, %e/$al!e)
AeGt

:btener todas las claves y valores de una coleccin IDictionary
Independientemente de que podamos recorrer los valores contenidos en una
coleccin de tipo IDictionary usando un objeto de tipo Dictionary%ntry, habr
ocasiones en las que realmente nos interesen tener solo los valores e incluso solo
las claves, en estos casos, podemos usar dos propiedades que la interfaz
IDictionary define: Keys y #alues. Estas propiedades devuelven un objeto del tipo
ICollection con las claves y valores respectivamente.
Al ser objetos ICollection, solo podremos usarlos para recorrerlos por medio de un
bucle )or %ac", ya que las colecciones ICollection no tienen ningn mtodo que nos
permita acceder a los elementos que contiene usando un ndice. En el siguiente
cdigo mostramos todas las claves de la coleccin creada en el ejemplo anterior:
)or ach cla5e As String In %ic/Ze-s
Console/<rite'ine(cla5e)
AeGt

235

Nota3
Siempre que usemos un bucle For Each para recorrer los elementos (o
datos) de una coleccin, solo tendremos acceso de solo lectura a esos
datos, es decir, no podremos modificarlos usando la varable por medio
de la que accedemos a ellos.


*as clases #ase para crear colecciones personali@adas
Tal como hemos visto, en el espacio de nombres System.Collections tenemos dos
clases abstractas que podemos usar como clases base para crear nuestras propias
colecciones.
Dependiendo que queramos crear una coleccin basada en IList, por ejemplo para
acceder a los elementos mediante un ndice numrico, o bien una coleccin basada
en IDictionary, para almacenar los elementos usando el par clave/valor, tendremos
que usar la clase CollectionBase o DictionaryBase.
Estas clases ya tienen cierta funcionalidad que podremos aprovechar para no tener
que reinventar la rueda, (esa es la "gracia" de la herencia), y lo nico que
tendremos que hacer es definir nuestros propios mtodos o propiedades para que la
coleccin acte como nosotros decidamos y, lo ms importante, para que solo
acepte los tipos de datos que realmente queramos.
236
Por ejemplo, si queremos almacenar datos de tipo Cliente y queremos acceder a
esos datos solo por un ndice numrico, podramos basar nuestra coleccin en
CollectionBase, pero si lo que necesitamos es una coleccin que contenga, por
ejemplo, objetos de tipo Artculo, nos podra interesar crear una coleccin basada
en DictionaryBase para que de esta forma podamos acceder a cada uno de los
elementos por medio del cdigo del artculo.
A continuacin veremos el cdigo (reducido) para crear estos dos tipos de
colecciones personalizadas.

Nota3
En las definiciones de las colecciones que vamos a mostrar, no hemos
aadido ninguna funcionalidad extra, sino que hemos creado las
clases/colecciones para que tengan un funcionamiento parecido al de
las colecciones "normales". La diferencia principal con esas colecciones
"normales" es que estas dos clases/colecciones que vamos a mostrar,
solo admitirn elementos de un tipo concreto.
Esto lo hemos hecho as para que podamos comparar y comprobar la
facilidad que ahora tenemos si usamos colecciones del espacio de
nombres System.Collection.Generic.


Crear una colecci(n basada en Collection.ase
A continuacin vamos a ver un ejemplo de una coleccin personalizada basada en
CollectionBase y cmo usarla. Esta coleccin almacenar elementos de un tipo
definido por nosotros: Cliente.
Primero veamos una clase Cliente muy simple, pero que implementa la interfaz
IComparable, de forma que se puedan clasificar sus elementos por el campo
Apellidos. Tambin define el mtodo ToString, ya que esta es una recomendacin
que siempre deberamos seguir, ya que muchas de las clases de punto NET utilizan
este mtodo para mostrar el contenido de los objetos.
444 (s!mmar-*
444 Clase Cliente
444 (Vs!mmar-*
444 (remarQs*
444 sta clase se 2!e%e clasi8icar 2or el cam2o A2elli%os
444 (VremarQs*
237
?!blic Class Cliente
Im2lements S-stem/ICom2arable
4
?!blic Aombre As String
?!blic A2elli%os As String
4
?!blic S!b AeJ(,-$al nombre As String, ,-$al a2elli%os As
String)
He/Aombre = nombre
He/A2elli%os = a2elli%os
n% S!b
4
?!blic 05erri%es )!nction 1oString() As String
"et!rn A2elli%os P ", " P Aombre
n% )!nction
4
?!blic )!nction Com2are1o(,-$al ob# As 0b#ect) As Integer +
Im2lements S-stem/ICom2arable/Com2are1o
I8 1-2e08 ob# Is Cliente 1hen
Dim cli As Cliente = DirectCast(ob#, Cliente)
"et!rn String/Com2are(He/A2elli%os, cli/A2elli%os)
lse
"et!rn 0
n% I8
n% )!nction
n% Class

En el siguiente cdigo tenemos la definicin de la clase/coleccin Clientes, que al
estar derivada de CollectionBase tendr todos los miembros definidos en esa clase
abstracta, (que solo se puede usar para crear clases derivadas); y en la que hemos
238
definido los mtodos ms habituales, as como una propiedad por defecto que nos
permite acceder a los elementos mediante un ndice numrico.
Como podemos comprobar, en los mtodos que hemos definido, realmente no
tenemos que hacer demasiadas cosas, ya que en el cdigo que hemos escrito en
esos nuevos miembros nos apoyamos en las colecciones internas proporcionadas
por la clase base:
List, que es una coleccin basada en IList que contiene los elementos, e InnerList
que es una coleccin de tipo *rrayList que tambin hace referencia a la coleccin
List.
En la propiedad Item, que es la propiedad predeterminada o indizador, cuando
devolvemos el valor indicado por el ndice numrico, tenemos que hacer una
conversin para que se devuelva un objeto de tipo Cliente en lugar de uno de tipo
Object que es como realmente se almacena en la coleccin.
444 (s!mmar-*
444 ColecciSn %e ti2o Cliente basa%a en I'ist
444 (Vs!mmar-*
444 (remarQs*(VremarQs*
?!blic Class Clientes
Inherits S-stem/Collections/Collection,ase

?!blic )!nction A%%(,-$al 5al!e As Cliente) As Integer
"et!rn 'ist/A%%(5al!e)
n% )!nction
?!blic )!nction Contains(,-$al 5al!e As Cliente) As ,oolean
"et!rn 'ist/Contains(5al!e)
n% )!nction
?!blic )!nction In%eG08(,-$al 5al!e As Cliente) As Integer
"et!rn 'ist/In%eG08(5al!e)
n% )!nction
239
?!blic S!b Insert(,-$al in%eG As Integer, ,-$al 5al!e As
Cliente)
'ist/Insert(in%eG, 5al!e)
n% S!b
De8a!lt ?!blic ?ro2ert- Item(,-$al in%eG As Integer) As
Cliente
;et
"et!rn DirectCast('ist(in%eG), Cliente)
n% ;et
Set(,-$al 5al!e As Cliente)
'ist(in%eG) = 5al!e
n% Set
n% ?ro2ert-
?!blic S!b "emo5e(,-$al 5al!e As Cliente)
'ist/"emo5e(5al!e)
n% S!b
?!blic S!b Sort()
Inner'ist/Sort()
n% S!b
n% Class

Para usar esta coleccin, lo haremos como es costumbre en las colecciones de tipo
IList:
S!b Hain()
Dim col As AeJ Clientes
col/A%%(AeJ Cliente("?e2e", "'S2e&"))
240
col/A%%(AeJ Cliente("'oli", "?Rre&"))
col/A%%(AeJ Cliente("5a", "Zelo"))
col/A%%(AeJ Cliente("@!an", "Sal5a%or"))
col/A%%(AeJ Cliente("Hig!el", "An%ra%e"))
col/Sort()
)or i As Integer = 0 1o col/Co!nt C 1
Console/<rite'ine(col(i)/A2elli%os)
AeGt
col/"emo5eAt(2)
)or ach cli As Cliente In col
Console/<rite'ine(cli/1oString)
AeGt
n% S!b


Crear una colecci(n basada en "ictionary.ase
En el siguiente cdigo veremos cmo definir una coleccin personalizada basada en
la clase abstracta DictionaryBase. Esta coleccin almacenar objetos del tipo
4rt,culo. Esos objetos se almacenarn indicando como clave el cdigo del artculo.
Veamos el cdigo y comentaremos las cosas dignas de resaltar.
La clase 4rticulo no tiene nada que resaltar, es una clase "normalita".
444 (s!mmar-*
444 Clase artKc!lo
444 (Vs!mmar-*
241
444 (remarQs*
444 Clase 2ara el e#em2lo %e colecciSn %eri5a%a %e Dictionar-,ase
444 (VremarQs*
?!blic Class Artic!lo
?!blic Co%igo As String
?!blic Descri2cion As String
?!blic ?$? As Decimal
S!b AeJ( ,-$al co%igo As String, +
,-$al %escri2cion As String, +
,-$al 2recio As Decimal)
He/Co%igo = co%igo
He/Descri2cion = %escri2cion
He/?$? = 2recio
n% S!b
?!blic 05erri%es )!nction 1oString() As String
"et!rn Co%igo P ", " P Descri2cion
n% )!nction
n% Class

La clase/coleccin la derivamos de DictionaryBase para que tenga todas las
"caractersticas" expuestas por esa clase abstracta, a la que le aadimos nuevos
mtodos y propiedades para darle funcionalidad. Tal como hicimos en la coleccin
Clientes, nos apoyamos en las colecciones internas de la clase base para realizar el
trabajo de esos nuevos miembros.
444 (s!mmar-*
444 ColecciSn Clientes basa%a en IDictionar-
444 (Vs!mmar-*
444 (remarQs*
242
444 (VremarQs*
?!blic Class Artic!los
Inherits S-stem/Collections/Dictionar-,ase
De8a!lt ?!blic ?ro2ert- Item(,-$al Qe- As String) As Artic!lo
;et
"et!rn DirectCast(Dictionar-(Qe-), Artic!lo)
n% ;et
Set(,-$al 5al!e As Artic!lo)
Dictionar-(Qe-) = 5al!e
n% Set
n% ?ro2ert-
?!blic "ea%0nl- ?ro2ert- Ze-s() As ICollection
;et
"et!rn Dictionar-/Ze-s
n% ;et
n% ?ro2ert-
?!blic "ea%0nl- ?ro2ert- $al!es() As ICollection
;et
"et!rn Dictionar-/$al!es
n% ;et
n% ?ro2ert-
?!blic S!b A%%(,-$al Qe- As String, ,-$al 5al!e As Artic!lo)
Dictionar-/A%%(Qe-, 5al!e)
n% S!b
243
?!blic )!nction Contains(,-$al Qe- As String) As ,oolean
"et!rn Dictionar-/Contains(Qe-)
n% )!nction
?!blic S!b "emo5e(,-$al Qe- As String)
Dictionar-/"emo5e(Qe-)
n% S!b
n% Class

La forma de usar esta coleccin es la misma que cualquier coleccin basada en
IDictionary.
Dim col As AeJ Artic!los
col/A%%("!no", AeJ Artic!lo("Fno", "Art/ Fno", 10/6D))
col/A%%("%os", AeJ Artic!lo("Dos", "Art/ Dos", 22))
col/A%%("tres", AeJ Artic!lo("1res", "Art/ 1res", .5/55D))
)or ach %e As Dictionar-ntr- In col
Dim art As Artic!lo
art = DirectCast(%e/$al!e, Artic!lo)
Console/<rite'ine("=0>, =1>, =2>", %e/Ze-, art/Descri2cion,
art/?$?)
AeGt
col/"emo5e("%os")
)or ach s As String In col/Ze-s
Console/<rite'ine("=0>, =1>", s, col(s)/Descri2cion)
AeGt
244


Crear colecciones personali*adas usando colecciones generic
Hasta esta versin de Visual Basic, si queramos crear colecciones "fuertemente
tipadas", es decir, colecciones que solo admitieran datos del tipo que nosotros
quisiramos, tenamos que hacerlo con un cdigo parecido al que hemos visto.
Pero si nuestra intencin es crear colecciones que "simplemente" contengan
elementos de un tipo determinado, por ejemplo objetos de tipo -liente o 4rticulo,
pero que no tengan ninguna funcionalidad extra a las que de forma predeterminada
tienen las clases base para crear colecciones, no es necesario que creemos nuestros
propias clases/coleccin, ya que Visual Basic 2005 puede crear colecciones con esas
caractersticas sin necesidad de crear un clase especfica.
Veamos primero el cdigo equivalente usando colecciones del espacio de nombres
1eneric con respecto a los dos tipos de colecciones anteriores, y despus
explicaremos un poco de que va todo esto de los generics.

La coleccin Clientes en versin "eneric
La coleccin Clientes es una coleccin que solo acepta elementos del tipo Cliente y a
la que podemos acceder mediante un ndice numrico, por tanto debemos buscar
una coleccin del espacio de nombres System.Collections.1eneric que nos ofrezca
esa misma funcionalidad, y esa coleccin es: List.
Debido a que las colecciones generic necesitan saber el tipo de datos que van a
almacenar, no necesitamos crear una clase/coleccin para almacenar los elementos
del tipo -liente, simplemente tendremos que indicar en el constructor de esa
coleccin que tipo debe contener.
En el siguiente cdigo tenemos la forma de declarar la coleccin de tipo List y cmo
acceder a los elementos que tienen, como podr comprobar es prcticamente el
mismo que el mostrado en el ejemplo de la coleccin basada en CollectionBase.
4 ColecciSn generic eI!i5alente a Arra-'ist
Console/<rite'ine("#em2lo !san%o ;eneric/'ist")
Dim colCli As AeJ S-stem/Collections/;eneric/'ist(08 Cliente)
colCli/A%%(AeJ Cliente("?e2e", "'S2e&"))
colCli/A%%(AeJ Cliente("'oli", "?Rre&"))
colCli/A%%(AeJ Cliente("5a", "Zelo"))
245
colCli/A%%(AeJ Cliente("@!an", "Sal5a%or"))
colCli/A%%(AeJ Cliente("Hig!el", "An%ra%e"))
colCli/Sort()
)or i As Integer = 0 1o colCli/Co!nt C 1
Console/<rite'ine(colCli(i)/A2elli%os)
AeGt
Console/<rite'ine()
4 limina el elemento %e la 2osiciSn 3
4 (2ero %es2!Rs %e haberlo clasi8ica%o)
colCli/"emo5eAt(2)
)or ach cli As Cliente In colCli
Console/<rite'ine(cli/1oString)
AeGt
El "quid" de la cuestin est en la forma de declarar la variable col-li, en la que le
indicamos que el tipo de datos que contendr la coleccin es "de" -liente:
Dim colCli As AeJ 'ist(08 Cliente)
Por lo dems, el cdigo a usar para acceder a los elementos, eliminarlos, etc., es el
mismo que con cualquier otra coleccin basada en IList, pero con el "detalle" de que
dicha coleccin "sepa" manejar elementos del tipo -liente.
Si no fuera as, esta lnea producira un error, ya que estamos accediendo a un tipo
de datos que define una propiedad llamada 4pellidos:
Console/<rite'ine(colCli(i).Apellidos)

246
La coleccin Articulos en versin "eneric
Como vimos, la coleccin 4rticulos solo acepta elementos del tipo 4rticulo, pero
como es una coleccin de tipo IDictionary cada vez que aadimos algn elemento o
queremos acceder a cualquiera de los contenidos en ella, debemos indicar tambin
una clave. Por tanto necesitamos una coleccin generic que tenga esas mismas
"caractersticas" y la que nos puede servir es la clase
System.Collections.1eneric.Dictionary.
A continuacin tenemos el cdigo para manejar objetos de tipo Articulo en una
coleccin tipo IDictionary, pero como veremos, en este caso hay que usar otra de
las clases del espacio de nombres 1eneric que nos sea til para hacer el bucle )or
%ac", ya que para usar la clase 1eneric.Dictionary debemos indicar tanto el tipo del
valor a almacenar como el de la clave.
Veamos el cdigo y despus entremos en ms detalles:
4 ColecciSn generic eI!i5alente a Hashtable (IDictionar-)
Console/<rite'ine("#em2lo !san%o ;eneric/Dictionar-")
Dim colArt As AeJ S-stem/Collections/;eneric/Dictionar-(08 String,
Artic!lo)
colArt/A%%("!no", AeJ Artic!lo("Fno", "Art/ Fno", 10/6D))
colArt/A%%("%os", AeJ Artic!lo("Dos", "Art/ Dos", 22))
colArt/A%%("tres", AeJ Artic!lo("1res", "Art/ 1res", .5/55D))
)or ach %e As Ze-$al!e?air(08 String, Artic!lo) In colArt
Dim art As Artic!lo
art = DirectCast(%e/$al!e, Artic!lo)
Console/<rite'ine("=0>, =1>, =2>", %e/Ze-, art/Descri2cion,
art/?$?)
AeGt
Console/<rite'ine()
colArt/"emo5e("%os")
)or ach s As String In colArt/Ze-s
247
Console/<rite'ine("=0>, =1>", s, colArt(s)/Descri2cion)
AeGt
Nuevamente "el truco" est en la forma de declarar la variable col4rt, en la que le
decimos que la coleccin Dictionary usar claves de tipo String y valores del tipo
4rticulo:
Dim colArt As AeJ Dictionar-(08 String, Artic!lo)
Para acceder a los elementos de esta coleccin por medio de un bucle )or %ac", en
lugar de usar una variable de tipo Dictionary%ntry debemos usar una del tipo
generic Key#alue+air en la que debemos especificar los tipos de datos que contiene
la coleccin:
)or ach %e As Ze-$al!e?air(08 String, Artic!lo) In colArt
Podemos comprobar que los tipos de datos que esta coleccin contiene son de tipo
String para las claves y de tipo Articulo para los valores, ya que al acceder a un
elemento dentro del segundo bucle, esos son los tipos de datos que deben tener, ya
que de lo contrario, no podramos acceder a la propiedad /escripcion del objeto
almacenado:
Console/<rite'ine("=0>, =1>", s, colArt(s).Descripcion)

248
-olecciones de tipo 'eneric 9en #reve:
En los ejemplos que acabamos de ver podemos apreciar que las colecciones del
espacio de nombres 1eneric son bastantes "potentes" o al menos nos pueden
facilitar la tarea de crear colecciones fuertemente tipadas, ya que podremos indicar
que tipo de datos son los que queremos que contenga.
En la siguiente imagen podemos ver cmo al declarar una coleccin
1eneric.Dictionary nos pide tanto el tipo de datos de la clave como del valor:
Fi'ura 0<.0$.0$ IntelliSense en las colecciones 'enerics
La principal ventaja de estas colecciones es que debemos indicar siempre el tipo de
datos que va a contener y en el caso de las colecciones Dictionary tambin tenemos
que indicar el tipo de datos para las claves.
Estos tipos de datos pueden ser cualquiera de los hay definidos en el propio .NET
Framework o los que hayamos definido nosotros.
Como podemos comprobar, siempre que vamos a declarar una coleccin 1eneric
vemos la "palabra clave" Of, esta instruccin lo que hace es indicar cual ser el tipo
de datos que contendr la coleccin. Y ese ser el nico tipo de datos que la
coleccin podr contener.

Eestricciones en los tipos generic
La ventaja de este tipo de "restriccin" del tipo que puede contener una coleccin
de tipo 1eneric es que en lugar de indicar un tipo concreto, podemos indicar
tambin un tipo algo ms "genrico", (genrico en el sentido de no tan estricto), por
ejemplo, si tenemos un tipo de datos que implementa una interfaz o que se deriva
de una clase, podemos indicar ese tipo despus de Of y en ese caso solamente se
admitirn objetos que implemente o se derive de ese tipo.
249
Por ejemplo, si tenemos una clase de tipo 8ersona y la utilizamos como clase base
de un tipo -liente y otro de tipo Empleado, podramos crear una coleccin
1eneric.List que admita solo elementos del tipo 8ersona, con lo cual podemos
hacer que podamos aadir tanto elementos de tipo -liente y/o de tipo Empleado,
ya que estas dos clases se derivan de la clase Persona.
En el siguiente cdigo tenemos las definiciones de estas tres clases y el cdigo para
crear la coleccin generic:
La clase Persona:
?!blic Class ?ersona
?ri5ate +Aombre As String
?!blic ?ro2ert- Aombre() As String
;et
"et!rn +Aombre
n% ;et
Set(,-$al 5al!e As String)
+Aombre = 5al!e
n% Set
n% ?ro2ert-
?ri5ate +A2elli%os As String
?!blic ?ro2ert- A2elli%os() As String
;et
"et!rn +A2elli%os
n% ;et
Set(,-$al 5al!e As String)
+A2elli%os = 5al!e
n% Set
n% ?ro2ert-
n% Class
La clase Cliente
?!blic Class Cliente
250
Inherits ?ersona
?!blic S!b AeJ(,-$al em2resa As String)
He/Aombre = em2resa
n% S!b
?!blic 05erri%es )!nction 1oString() As String
"et!rn Aombre
n% )!nction
n% Class
La clase Empleado
?!blic Class m2lea%o
Inherits ?ersona
?!blic S!b AeJ(,-$al nombre As String, ,-$al a2elli%os As
String)
He/Aombre = nombre
He/A2elli%os = a2elli%os
n% S!b
?!blic 05erri%es )!nction 1oString() As String
"et!rn A2elli%os P ", " P Aombre
n% )!nction
n% Class

El cdigo para usar estas clases
Dim col As AeJ S-stem/Collections/;eneric/'ist(08 ?ersona)
251
col/A%%(AeJ Cliente("Constr!cciones ?e2e"))
col/A%%(AeJ m2lea%o("@!an", "?Rre&"))
)or ach 2 As ?ersona In col
Console/<rite'ine(2/Aombre)
AeGt

Las colecciones y clases generic son bastantes "potentes" y en principio fciles de
utilizar, con el valor aadido (o ventaja) es que nosotros tambin podemos crear
nuestros propios tipos de datos que utilicen esta nueva "tecnologa", pero su
tratamiento en profundidad sobrepasa el objetivo de este curso, aunque con lo aqu
expuesto creemos que el lector est preparado para investigar por su cuenta, con la
ayuda de la documentacin de Visual Basic 2005 Express y de los muchos recursos
que en breve estarn disponibles tanto en formato "artculo Web" y en libros
especializados en las novedades de Visual Basic 2005.


Introduccin
Al empezar a trabajar con .NET, uno de los "grandes" cambios que notaremos los
que estamos habituados a desarrollar con Visual Basic 6.0 es todo lo relacionado
252
con el acceso al contenido de los ficheros.
En VB6 no tenemos demasiadas complicaciones, simplemente utilizamos las
funciones para acceder a los ficheros y poco ms, pero en .NET, y por tanto en
Visual Basic 2005, el acceso a ficheros se extiende con otros conceptos que en VB6
no tenemos, salvo que nos atrevamos con las APIs de Windows y la
"interoperabilidad" con el lenguaje C/C++, estamos hablando de los streams (o
usando la traduccin de la documentacin: las secuencias).
Con los streams no solo podemos acceder a los ficheros de disco, sino que tambin
podemos acceder a otros tipos de "secuencias" o flujos de datos, desde streams de
memoria a streams para enviar informacin a travs de Internet.
Toda esta transmisin o flujo de informacin se realiza mediante una serie de
mtodos de lectura y escritura que estn bsicamente encapsulados en la clase
abstracta Stream.
Esta clase ser la clase base de todas aquellas que de alguna forman tienen que
transmitir cierta informacin entre la fuente de datos y nuestra aplicacin.
En este captulo trataremos de las clases basadas en Stream que con ms
frecuencia utilizaremos, sobre todo en lo relacionado con el acceso a ficheros, que
es al fin y al cabo la utilidad principal de este tipo de "secuencias".


Streams en .NET
Streams en .NET
'as clases basadas en Stream
o Manejar un fichero usando FileStream
o Manejar un fichero usando StreamReader y StreamWriter
Asegurarnos que el fichero se cierra
Liberar recursos: Using... End Using
o Ejemplo de para cifrar y descifrar un fichero

*as clases #asadas en Stream
Entre las clases que estn basadas en esta clase abstracta tenemos las siguientes:
BufferedStream, clase abstracta que representa un buffer de almacenamiento
para operaciones de lectura y escritura de otro stream.
DeflateStream, permite la compresin y descompresin de streams usando el
algoritmo Deflat.
1QipStream, usada para comprimir y descomprimir streams.
)ileStream, nos permite una forma bsica de acceder y manipular ficheros.
253
(emoryStream, crear un stream que se almacena en la memoria como una
secuencia de bytes.
$et!or6Stream, proporciona una secuencia de datos para el acceso a la red.
CryptoStream, un stream usado para encriptar otros streams.

Nota3
Las clases DeflateStream y GZipSteam estn incluidas en el espacio de
nombres System.IO.Compression.
La clase CryptoStream est incluida en el espacio de nombres
System.Security.Cryptography.
La clase NetworkStream est incluida en el espacio de nombres
System.Net.Sockets.

Adems de estas clases que se derivan directamente de la clase Stream, y que
normalmente se usan como "secuencias" a usar por otras clases de entrada/salida,
tenemos otras que nos permitirn acceder a esas secuencias de datos de una forma
ms directa, (algunas de estas las veremos con algo de ms detalle en el prximo
captulo dedicado al sistema de archivos de .NET), por ejemplo:
Binary'eader 5 Binary4riter, lee o escribe tipos primitivos como valores
binarios utilizando una codificacin especfica.
Stream'eader 5 Stream4riter, clases para leer y escribir caracteres en
ficheros utilizando una codificacin determinada.
String'eader 5 String4riter, implementa Te&t'eader o Te&t4riter para leer o
escribir en una cadena.
Te&t'eader 5 Te&t4riter, clases abstractas para leer o escribir en una
secuencia de caracteres.

Cuando trabajamos con los streams debemos olvidarnos de las "cosas simples" y
debemos tener en cuenta que trataremos casi siempre con secuencias de bytes, ya
que al fin y al cabo esa es la forma de almacenar la informacin en los streams. Por
tanto cuando veamos los ejemplos que la documentacin de Visual Basic 2005 nos
proporciona no debemos extraarnos de que haya que hacer tantas "cosas" para
acceder o manipular la informacin almacenada en esas "secuencias" de datos. Si
bien, esa "complicacin" nos da mayor control sorbe el formato de la informacin
contenida en los streams. Por suerte, para los que nos gustan las cosas "simples"
las clases especficas nos facilitan mucho las cosas.
A continuacin veremos un par de ejemplos en los que manipularemos cierta
informacin tanto en la memoria usando un objeto del tipo (emoryStream, como
en un fichero de disco usando )ileStream y las clases que casi con seguridad
usaremos habitualmente para acceder al contenido de los ficheros: Stream'eader y
Stream4riter.
254


%anear un fic#ero usando <ileStream
En este primer ejemplo veremos lo complicado que pude parecer acceder a un
fichero usando la clase )ileStream y por extensin cualquier mtodo de otras clases
que devuelvan este tipo de secuencia, como por ejemplo los mtodos Open'ead,
Open4rite, etc. de la clase File.
La "complejidad" de esta clase es que realmente obtiene o guarda la informacin
por medio de un array de tipo Byte, cuando a lo que estamos acostumbrados es a
usar cadenas.

Nota3
Realmente, esta forma "binaria" de acceder a la informacin de un
fichero no la tenemos que ver como un inconveniente, ya que nos
puede servir para acceder de forma "binaria" a ese fichero, en caso de
que nuestra intencin sea acceder de forma "normal" para, por
ejemplo, leer solo texto, deberamos usar otras clases ms
especializadas para esa tarea, como lo es StreamReader.

En el siguiente cdigo tenemos dos mtodos, uno que guarda una cadena en el
fichero indicado:
?ri5ate S!b g!ar%arDatos(,-$al 8ichero As String, ,-$al ca%ena As
String)
4 Abrimos o creamos el 8ichero, 2ara escribir en Rl
Dim 8s As AeJ S-stem/I0/)ileStream(8ichero, +
S-stem/I0/)ileHo%e/02en0rCreate, +
S-stem/I0/)ileAccess/<rite)
4 scribimos alg!nas ca%enas,
4 el 2roblema es I!e solo 2o%emos escribir arra-s %e b-tes,
4 2or tanto %ebemos con5ertir la ca%ena en !n arra- %e b-tes
Dim %atos() As ,-te
4 2ero !san%o la co%i8icaciSn I!e creamos con5eniente
4 %e 8orma 2re%etermina%a es F1)CX,
255
4 a!nI!e la co%i8icaciSn %e <in%oJs es AASI (nco%ing/De8a!lt)
Dim enc As AeJ S-stem/1eGt/F1)Xnco%ing
4 con5ertimos la ca%ena en !n arra- %e b-tes
%atos = enc/;et,-tes(ca%ena)
4 lo escribimos en el stream
8s/<rite(%atos, 0, %atos/'ength)
4 nos aseg!ramos I!e se escriben to%os los %atos
8s/)l!sh()
4 cerramos el strema
8s/Close()
n% S!b
En el constructor de la clase )ileStream indicamos el fichero en el que
queremos guardar la informacin, tambin le indicamos que queremos crearlo
o abrirlo, es decir, si ya existe lo abre y si no existe lo crea, de cualquiera de
las formas, en el siguiente parmetro del constructor le indicamos que
nuestra intencin es escribir en ese fichero.
Como hemos comentado, la clase )ileStream (y en general todos los streams)
trabaja con bytes, por tanto para poder almacenar algo en ese fichero
debemos hacerlo mediante un array de tipo Byte.
En el caso de las cadenas, stas siempre deben estar codificadas, es decir,
deben usar el juego de caracteres que creamos conveniente, en el mundo
de .NET ese juego de caracteres es Unicode, ms concretamente usando la
codificacin UTF-8, la cual permite trabajar con cualquier carcter de
cualquier cultura.
Como lo que nos interesa es convertir una cadena en un array de bytes,
usamos el mtodo 1etBytes de un objeto ,T)R%ncoding, el cual convierte la
cadena en una "ristra" de bytes con el formato adecuado, en este caso UTF-8.
Si en lugar de usar UTF-8 quisiramos usar otro "codificador", por ejemplo el
predeterminado de Windows, con idea de que los ficheros sean compatibles
con nuestras aplicaciones de VB6, tendremos que declarar la variable
enconding de la siguiente forma:
Dim enc As S-stem/1eGt/nco%ing = S-stem/1eGt/nco%ing/De8a!lt
A continuacin, simplemente le pasamos el array de bytes al mtodo 4rite
del )ileStream indicando desde que posicin de dicho array debe escribir y
cuantos bytes.
Por ltimo nos aseguramos de que todos los bytes del "buffer" se guarden en
el fichero y lo cerramos.

Y otra funcin que devuelve el contenido de un fichero en formato cadena:
256
?ri5ate )!nction leerDatos(,-$al 8ichero As String) As String
4 'os bloI!es leK%os los almacenaremos en !n String,!il%er
Dim res As AeJ S-stem/1eGt/String,!il%er
4 Abrimos el 8ichero 2ara leer %e Rl
Dim 8s As AeJ S-stem/I0/)ileStream(8ichero, +
S-stem/I0/)ileHo%e/02en, +
S-stem/I0/)ileAccess/"ea%)
4 los %atos se leer6n en bloI!es %e 102. b-tes (1 Z,)
Dim %atos(102.) As ,-te
Dim enc As AeJ S-stem/1eGt/F1)Xnco%ing()
4 leemos mientras ha- algo en el 8ichero
<hile 8s/"ea%(%atos, 0, 102.) * 0
4 agregamos al string,!il%er los b-tes leK%os
4 (con5erti%os en !na ca%ena)
res/A22en%(enc/;etString(%atos))
n% <hile
4 cerramos el b!88er
8s/Close()
4 %e5ol5emos to%o lo leK%o
"et!rn res/1oString
n% )!nction
En esta funcin vamos a leer los datos del fichero indicado, como ya hemos
vistos, la clase )ileStream trabaja con bytes y esos bytes los convertimos a
caracteres por medio de las clases de codificacin especializadas.
Por regla general, esas lecturas las haremos de forma parcial, es decir
leyendo bloques de bytes y como tenemos que convertir esos bytes en
caracteres, y puede ser que el fichero sea muy grande, en lugar de
concatenar una cadena para almacenar las lecturas parciales, vamos a usar
un objeto del tipo StringBuilder en el que iremos "agregando" cada trozo
ledo, de forma que el rendimiento no se vea penalizado por la forma de ser
de las cadenas, ya que cada vez que hacemos una concatenacin en una
variable de tipo String, realmente estamos creando nuevos objetos en la
memoria y si son muchos, pues la verdad es que tendremos al recolector de
basura (GC) trabajando a tope, y si usamos un objeto StringBuilder el
rendimiento mejora una barbaridad.
257
La lectura de cada bloque de bytes lo hacemos en un bucle 4"ile, tambin
podramos haberlo hecho en un bucle Do 4"ile, pero en estos casos, el
rendimiento de 4"ile es un "poquitn" mayor.
Los datos ledos los agregamos al objeto StringBuilder por medio del mtodo
*ppend que se encarga de agregarlo a la cadena interna.
Finalmente cerramos el stream y devolvemos la cadena leda.

Para usar estas dos funciones lo podemos hacer de la siguiente forma:
4 !n 8ichero %e e#em2lo (el %irectorio %ebe eGistir)
Const 8ichero As String = "DU?r!ebasU2r!eba/tGt"
4 g!ar%amos !na ca%ena en el 8ichero
g!ar%arDatos(8ichero, "Hola, H!n%o %e )ileStream")
4
4 'eemos el conteni%o %el 8ichero - lo mostramos
Console/<rite'ine(leerDatos(8ichero))
Este cdigo no necesita mayor explicacin.


%anear un fic#ero usando StreamEeader y StreamJriter
A continuacin veremos cmo crear las dos funciones del ejemplo anterior para que
utilicen las clases "especializadas" para leer y escribir cadenas en un fichero.
Como podremos comprobar, esta es una forma muchsimo ms simple y, por tanto
recomendada para este tipo de acceso a los ficheros. Aunque debemos recordar que
solo servir para leer la informacin de forma secuencial y en formato cadena.

Nota3
El cdigo para usar estas dos funciones ser el mismo que el usado
para las funciones que utilizan la clase FileStream.


La funcin para guardar una cadena en un fichero:
258
?ri5ate S!b g!ar%arDatos(,-$al 8ichero As String, ,-$al ca%ena As
String)
4 Abrimos el 8ichero 2ara escribir, (no aTa%ir),
4 !san%o la co%i8icaciSn 2re%etermina%aD F1)CX
Dim sJ As AeJ S-stem/I0/Stream<riter(8ichero, )alse)
4 g!ar%amos to%a la ca%ena
sJ/<rite'ine(ca%ena)
4 Cerramos el 8ichero
sJ/Close()
n% S!b
Como podemos apreciar, esta es una forma mucho ms "compacta" que la anterior,
ya que solo tenemos que indicar en el constructor lo que queremos hacer y usar el
mtodo 4rite o 4riteLine para guardar lo que queramos en el fichero.
Para guardarlo usando la codificacin predeterminada del Sistema Operativo en el
que se utilice la aplicacin, (en Windows ser ANSI), simplemente usamos este
constructor:
Dim sJ As AeJ S-stem/I0/Stream<riter(8ichero, )alse,
S-stem/1eGt/nco%ing/De8a!lt)

Para leer los datos podemos hacerlo de dos formas: lnea a lnea o todo el contenido
de una sola vez.
En el cdigo siguiente se muestra lnea a lnea, y al final, (comentado), cmo
hacerlo en una sola pasada.
?ri5ate )!nction leerDatos(,-$al 8ichero As String) As String
4 Abrimos el 8ichero 2ara leer
4 !san%o la co%i8icaciSn F1)CX (la 2re%etermina%a %e /A1)
Dim sr As AeJ S-stem/I0/Stream"ea%er(8ichero, 1r!e)
4 si I!eremos !sar la 2re%etermina%a %e <in%oJs
4Dim sr As AeJ S-stem/I0/Stream"ea%er(8ichero,
S-stem/1eGt/nco%ing/De8a!lt)
4 ?o%emos leer ca%a !na %e las lKneas %el 8ichero o to%o el
conteni%o
4 )orma largaD
259
4 si 5amos a leer el 8ichero lKnea 2or lKnea, me#or !sar !n
String,!il%er
Dim ret As AeJ S-stem/1eGt/String,!il%er
4 recorremos el 8ichero hasta I!e no ha-a na%a I!e leer
<hile sr/?eeQ (* C1
ret/A22en%(sr/"ea%'ine)
n% <hile
4 cerramos el 8ichero
sr/Close()
4 %e5ol5emos lo leK%o
"et!rn ret/1oString
4
44 )orma cortaD
44 leemos to%o el conteni%o %el 8ichero
4Dim ret As String = sr/"ea%1on%()
44 lo cerramos
4sr/Close()
44 %e5ol5emos lo leK%o
4"et!rn ret
n% )!nction
Si nos decidimos a leer el contenido del fichero lnea a lnea, podemos usar el
mtodo +ee6, el cual devolver el siguiente carcter del buffer del stream, o -1 si no
hay nada que leer. +ee6 no "consume" el carcter, simplemente comprueba si hay
algo que leer.
Si hay algo que leer, leemos la lnea completa y la aadimos al objeto StringBuilder,
el bucle se repetir mientras haya informacin pendiente de leer.
Pero si optamos por la va rpida, porque realmente no nos interese procesar cada
lnea, podemos usar el mtodo 'eadTo%nd, que en nuestro ejemplo, el valor
devuelto ser todo el contenido del fichero, el cual asignamos a una variable de tipo
String para usarla como valor devuelto por la funcin, despus de cerrar el fichero.

260
Ase"urarnos que el fic%ero se cierra
Si queremos ahorrarnos el paso intermedio de asignar el valor en una variable y
despus devolverlo, tambin podemos hacerlo de esta forma:
1r-
"et!rn sr/"ea%1on%()
)inall-
sr/Close()
n% 1r-
Ya que el mtodo )inally siempre se ejecutar, por tanto nos aseguramos de que el
fichero se cierra.

Liberar recursos: Gsin"*** nd Gsin"
O si lo preferimos, podemos usar la nueva forma de asegurarnos de que los
recursos usados se liberan:
4 ?o%emos !sar Fsing 2ara aseg!rarnos %e I!e el rec!rso se libera
?ri5ate )!nction leerDatos(,-$al 8ichero As String) As String
Dim sr As AeJ S-stem/I0/Stream"ea%er(8ichero, 1r!e)
Fsing sr
"et!rn sr/"ea%1on%()
n% Fsing
n% )!nction
En este cdigo, cuando usamos Gsin' sr, al ejecutarse End Gsin', el CLR se
encargar de llamar al mtodo Dispose de la clase, de forma que se liberen los
recursos que estemos usando, en este ejemplo: el fichero abierto.
Estos dos cdigos seran equivalentes, ms seguros, pero tambin con ms
"trabajo" para el CLR.

Nota3
Using... End Using solo se puede usar con clases que implementen la
interfaz IDisposable, que es la que asegura que el objeto implementa
261
el mtodo Dispose.
Por tanto, si implementamos el mtodo IDisposable.Dispose en
nuestras clases, en ese mtodo nos tenemos que asegurar que
liberamos los recursos que nuestra clase est utilizando.


Eemplo de para cifrar y descifrar un fic#ero
En el siguiente ejemplo (adaptado de uno de la documentacin), veremos cmo
usar algunas de las clases basadas en Stream, particularmente las clase
(emoryStream, )ileStream, CryptoStream adems de las clases Stream'eader y
Stream4riter.
Este cdigo tiene dos funciones:
La primera encripta (cifra) una cadena y la guarda en un fichero.
La segunda desencripta (descifra) el contenido de un fichero y lo guarda en otro.
Ambas funciones devuelven la cadena cifrada o descifrada respectivamente.
Im2orts S-stem
Im2orts S-stem/I0
Im2orts S-stem/1eGt
Im2orts S-stem/Sec!rit-/Cr-2togra2h-
Ho%!le Ho%!le1
Const 8ic1 As String = "DU?r!ebasU?r!eba Cr-2toStream/tGt"
Const 8ic3 As String = "DU?r!ebasU?r!eba Cr-2toStream
%es/tGt"
Const sZe- As String = "l 2assJor% a !sar"
4
S!b Hain()
Dim ret As String
4
ret = ci8rar)ichero("Hola, H!n%o encri2ta%o", 8ic1)
Console/<rite'ine("Ca%ena encri2ta%a D =0>", ret)
4
262
ret = %esci8rar)ichero(8ic1, 8ic3)
Console/<rite'ine("Ca%ena %esencri2ta%aD =0>", ret)
4
Console/"ea%'ine()
n% S!b
)!nction ci8rar)ichero( +
,-$al teGto As String, +
,-$al 8icSali%a As String) As String
4 Creamos !n Hemor-Sream con el teGto a ci8rar
Dim enc As AeJ F1)Xnco%ing
Dim %atos() As ,-te = enc/;et,-tes(teGto)
Dim ms As AeJ Hemor-Stream(%atos)
4 l 8ichero %e sali%a
Dim 8s As AeJ )ileStream(8icSali%a, )ileHo%e/Create,
)ileAccess/<rite)
4 l 2ro5ee%or cri2togr68ico
Dim r As AeJ DSCr-2toSer5ice?ro5i%er
4
4 stablecer la cla5e secreta
r/Ze- = nco%ing/De8a!lt/;et,-tes(sZe-/S!bstring(0, X))
r/I$ = nco%ing/De8a!lt/;et,-tes(sZe-/S!bstring(0, X))
4
4 Crear !na sec!encia %e ci8ra%o
Dim cs As AeJ Cr-2toStream(8s, +
r/Createncr-2tor(), +
Cr-2toStreamHo%e/<rite)
4
4 scribir el 8ichero ci8ra%o
263
cs/<rite(%atos, 0, %atos/'ength)
cs/Close()
4
4 %e5ol5er el teGto ci8ra%o
"et!rn Con5ert/1o,ase6.String(ms/1oArra-())
n% )!nction
)!nction %esci8rar)ichero( +
,-$al 8ichero As String, +
,-$al 8icSali%a As String) As String
4 el 2ro5ee%or %el ci8ra%o - las cla5es !sa%as 2ara ci8rar
Dim r As AeJ DSCr-2toSer5ice?ro5i%er
r/Ze-() = nco%ing/De8a!lt/;et,-tes(sZe-/S!bstring(0, X))
r/I$ = nco%ing/De8a!lt/;et,-tes(sZe-/S!bstring(0, X))
4
4 crear la sec!encia 2ara leer el 8ichero ci8ra%o
Dim 8s As AeJ )ileStream(8ichero, )ileHo%e/02en,
)ileAccess/"ea%)
4
Dim cs As AeJ Cr-2toStream(8s, +
r/CreateDecr-2tor(), +
Cr-2toStreamHo%e/"ea%)
4
4 g!ar%ar el conteni%o %e 8ichero %esci8ra%o
Dim sJ As AeJ Stream<riter(8icSali%a)
Dim sr As AeJ Stream"ea%er(cs)
sJ/<rite(sr/"ea%1on%)
sJ/)l!sh()
sJ/Close()
264
4
4 %e5ol5er el teGto
sr = AeJ Stream"ea%er(8ic3)
Dim ret As String = sr/"ea%1on%()
sr/Close()
4
"et!rn ret
n% )!nction
n% Ho%!le

Introduccin
En la leccin anterior vimos cmo podemos acceder al contenido de los ficheros, es
decir, cmo leer lo que hay dentro de un fichero, e incluso cmo haremos para
escribir en ellos. En esta leccin trataremos del acceso al sistema de archivos, es
decir, veremos las clases que .NET pone a nuestra disposicin para que podamos
manejar tanto los ficheros (archivos) como los directorios.
Los que hayan utilizado el objeto )ile System Objects desde Visual Basic 6.0
seguramente encontrarn muchas similitudes con lo que .NET ofrece, pero, como
265
comprobaremos, en .NET tenemos ms variedad de clases y, por supuesto,
podemos hacer muchas ms cosas, y de forma ms fcil, que desde VB6.


4cceso al sistema de arc?ivos
Acceso al sistema de arc#ivos
'as clases del espacio de nombres System.-$
o Clases para manipular unidades, directorios y ficheros
o Las clases para crear streams
o Las clases para leer o escribir en los streams
Clases para manipular unidades/ directorios y fic#eros
o Las clases Directory y DirectoryInfo
Los mtodos de las clases Directory y DirectoryInfo
o Las clases File y FileInfo
Cifrar y descifrar un fichero usando File o FileInfo
Abrir ficheros para agregar o leer el contenido
o Manipular cadenas relacionadas con ficheros y directorios usando Path
'as clases para leer o escribir en los streams
o Las clases StreamReader y StreamWriter
La codificacin de los ficheros de .NET
El obeto %y
o El objeto My.Computer.FileSystem
Buscar texto en ficheros con FindInFiles
Examinar el contenido de un fichero con formato con
OpenTextFieldParse

266

4cceso al sistema de arc?ivos
Empezaremos viendo las las clases elementales o ms usadas para manejar el
sistema de archivos desde .NET.
El espacio de nombres System.IO es el que contiene todas las clases relacionadas
con los ficheros y directorios, en ese mismo espacio de nombres estn las que
vimos en la leccin anterior dedicada a los streams de .NET, ya que al fin y al cabo,
cuando tratamos con los ficheros, estaremos tratando con una secuencia de
caracteres o bytes, secuencia a la que accederemos con las clases especializadas
que ya vimos.
Aqu nos centraremos principalmente en la forma de acceder a esos ficheros, a
copiarlos, a comprobar si existen, etc., en definitiva: a manipularlos.


*as clases del espacio de nom#res S%stem.I7
Entre las clases que nos podemos encontrar en este espacio de nombres, tenemos
clases que podemos agrupar dependiendo de las tareas que podemos hacer con
ellas en:
Las clases para manipular las unidades, directorios y ficheros
Las clases para crear streams
Las clases para leer o escribir en los streams
267
Veamos primero una relacin de esas clases y enumeraciones y despus veremos
algunas de ellas con ms detalle.

Clases para manipular unidades/ directorios y fic#eros
Entre las clases que nos permiten trabajar con los ficheros, directorios y las
unidades de disco, podemos destacar las siguientes:
Directory, proporciona mtodos estticos para crear, mover y enumerar los
ficheros de directorios y subdirectorios.
DirectoryInfo, al igual que la clase Directory, pero los mtodos son de
instancia, dicha instancia se crear a partir de un directorio determinado.
DrieInfo, proporciona mtodos de instancia para crear, mover y enumerar el
contenido de unidades.
)ile, proporciona mtodos estticos para crear, copiar, eliminar, mover y abrir
ficheros, adems de ayudar a la creacin de objetos )ileStream.
)ileInfo, igual que la clase )ile, pero los mtodos son de instancia, dicha
instancia se crear a partir de un fichero determinado.
+at", proporciona mtodos y propiedades para procesar cadenas relacionadas
con los directorios.
Tambin tenemos las siguientes enumeraciones:
)ile*ccess, define constantes para el tipo de acceso a los ficheros: lectura,
escritura o lectura/escritura.
)ile*ttributes, define constantes para el atributo de los ficheros y directorios:
archivo, oculto, solo lectura, etc.
)ile(ode, define las constantes que podemos usar para controlar como
abrimos un fichero.
)ileS"are, define las constantes para controlar el tipo de acceso que otros
objetos )ileStream pueden tener al mismo fichero.

'as clases para crear streams
La siguiente relacin son clases que nos permiten la creacin de streams, las cuales
ya vimos en la leccin anterior, por tanto solo las mencionaremos.
BufferedStream, clase abstracta que representa un buffer de almacenamiento
para operaciones de lectura y escritura de otro stream.
DeflateStream, permite la compresin y descompresin de streams usando el
algoritmo Deflat.
1QipStream, usada para comprimir y descomprimir streams.
)ileStream, nos permite una forma bsica de acceder y manipular ficheros.
(emoryStream, crear un stream que se almacena en la memoria como una
secuencia de bytes.
$et!or6Stream, proporciona una secuencia de datos para el acceso a la red.
268
CryptoStream, un stream usado para encriptar otros streams.

'as clases para leer o escribir en los streams

Binary'eader, lee tipos primitivos o cadenas codificadas desde un )ileStream.
Binary4riter, escribe tipos primitivos o cadenas codificadas en un )ileStream.
Stream'eader, lee caracteres desde un )ileStream, usando codificacin para
convertir los caracteres a/desde bytes.
Stream4riter, escribe caracteres a un )ileStream, usando codificacin para
convertir los caracteres en bytes.
String'eader, lee caracteres desde un String. La salida puede ser a un stream
en cualquier codificacin o a una cadena.
String4riter, escribe caracteres a un String. Al igual que String'eader, la
salida puede ser a un stream usando cualquier codificacin o a una cadena.

Te&t'eader, es la clase abstracta base para Stream'eader y String'eader.
Te&t4riter, es la case abstracta base para Stream4riter y String4riter.

Nota3
La clase abstracta Stream est diseada para entrada y salida de
bytes, las clases abstractas TextReader y TextWriter estn diseadas
para la entrada/salida de caracteres Unicode.

269

-lases para manipular unidadesC directorios % fic?eros
Entre las clases que nos permiten trabajar con los ficheros, directorios y las
unidades de disco, podemos destacar las siguientes:
Directory, proporciona mtodos estticos para crear, mover y enumerar los
ficheros de directorios y subdirectorios.
DirectoryInfo, al igual que la clase Directory, pero los mtodos son de
instancia, dicha instancia se crear a partir de un directorio determinado.
DrieInfo, proporciona mtodos de instancia para crear, mover y enumerar el
contenido de unidades.
File, proporciona mtodos estticos para crear, copiar, eliminar, mover y abrir
ficheros, adems de ayudar a la creacin de objetos )ileStream.
)ileInfo, igual que la clase )ile, pero los mtodos son de instancia, dicha
instancia se crear a partir de un fichero determinado.
+at", proporciona mtodos y propiedades para procesar cadenas relacionadas
con los directorios.
Tambin tenemos las siguientes enumeraciones:
)ile*ccess, define constantes para el tipo de acceso a los ficheros: lectura,
escritura o lectura/escritura.
)ile*ttributes, define constantes para el atributo de los ficheros y directorios:
archivo, oculto, solo lectura, etc.
)ile(ode, define las constantes que podemos usar para controlar como
abrimos un fichero.
)ileS"are, define las constantes para controlar el tipo de acceso que otros
objetos )ileStream pueden tener al mismo fichero.
270


'as clases "irectory y "irectory-nfo
Cuando necesitemos acceder a un directorio, por ejemplo, para saber que
subdirectorios y ficheros contiene o para obtener otro tipo de informacin, incluso
para saber si existe o no, en esos casos podemos utilizar las clases Directory o
DirectoryInfo.
La primera de ellas: Directory, proporciona mtodos estticos, es decir, los mtodos
que contienen siempre estarn disponibles sin necesidad de crear una nueva
instancia de la clase. Por tanto, podremos usar esos mtodos simplemente usando
la propia clase.
La segunda: DirectoryInfo, proporciona los mismos mtodos que Directory, pero en
lugar de ser mtodos estticos, son mtodos de instancia, es decir, esos mtodos
solamente se podrn usar despus de haber creado una instancia (u objeto en
memoria) de esta clase.
Cada una de las instancias de DirectoryInfo, har referencia a un directorio en
particular, ese directorio se indicar al crear el objeto, aunque tambin puede ser
que est referenciado al obtenerlo mediante otros mtodos que devuelven este tipo
de objetos.

Nota3
El directorio asignado al crear la instancia de DirectoryInfo no tiene
porqu existir.
De esa forma podemos comprobar si existe, y en caso de que no
exista, crearlo, etc.

Por ejemplo, si queremos saber si un directorio existe, utilizaremos el mtodo
%&ists, en el caso de la clase Directory, como parmetro le indicaremos el directorio
del que queremos comprobar su existencia, sin embargo, si usamos un objeto del
tipo DirectoryInfo, no necesitamos indicar ningn parmetro, ya que el directorio
que est asociado con esa clase lo habremos indicado al crear el objeto.
En el siguiente cdigo vemos cmo usar estas dos clases:
Const %ir1 As String = "DU?r!ebas"
Const %ir2 As String = "DU?r!ebas2"
S!b Hain()
271
claseDirector-()
Console/<rite'ine()
claseDirector-In8o()
Console/<rite'ine()
4
Console/"ea%'ine()
n% S!b
S!b claseDirector-()
4 'os mRto%os %e la clase Director- son est6ticos,
4 2or tanto no necesitamos crear !na instancia %e esta clase
4
4 Com2robar si eGiste !n %irectorioD
I8 S-stem/I0/Director-/Gists(%ir1) 1hen
Console/<rite'ine("l %irectorio 4=0>4 SI eGiste", %ir1)
lse
Console/<rite'ine("l %irectorio 4=0>4 A0 eGiste", %ir1)
n% I8
n% S!b
S!b claseDirector-In8o()
4 'os mRto%os %e la clase Director-In8o son %e instancia,
4 2or tanto tenemos I!e crear !na instancia %e la clase
4 2ara 2o%er !sarla
4
Dim %i As AeJ S-stem/I0/Director-In8o(%ir2)
4
4 Com2robar si eGiste !n %irectorioD
I8 %i/Gists 1hen
272
Console/<rite'ine("l %irectorio 4=0>4 SI eGiste", %ir2)
lse
Console/<rite'ine("l %irectorio 4=0>4 A0 eGiste", %ir2)
n% I8
n% S!b

El resto de mtodos de estas dos clases funcionan de forma similar, al menos en el
sentido de que si usamos la clase Directory, siempre habr un parmetro que haga
referencia al directorio que queremos usar, mientras que con DirectoryInfo siempre
estar haciendo referencia al directorio usado al crear la instancia.

Nota3
No queremos parecer repetitivos, pero nos interesa &ue &uede
claro como funcionan este tipo de clases, que por otro lado, ser
similar al de las clases File y FileInfo, al menos en el sentido de que la
clase con los mtodos estticos siempre necesitar saber a que
elemento del sistema de archivos estamos refirindonos, mientras que
las clases que debemos instanciar, siempre sabrn con que elemento
trabajarn.


Los mtodos de las clases Directory y DirectoryInfo
Estas clases siempre manejarn directorios y entre los mtodos que podemos
utilizar, destacamos los siguientes, empezamos por la clase Directory:
CreateDirectory, crear los directorios indicados en el parmetro. Si algunos de
los directorios intermedios no existen, los crear.
%&ists, comprueba si el directorio indicado existe.
1etCreationTime, devuelve la fecha y hora de creacin del directorio indicado.
1etCreationTime,tc, devuelve la fecha y hora universal (UTC/GMT) de
creacin del directorio.
1etCurrentDirectory, devuelve el directorio de trabajo de la aplicacin.
1etDirectories, devuelve un array de String con todos los subdirectorios del
directorio indicado. Se puede indicar un "pattern" de bsqueda y si queremos
incluir los subdirectorios que tenga el directorio indicado.
1etDirectory'oot, devuelve el directorio raz del directorio indicado.
1et)iles, devuelve un array de tipo String con los ficheros del directorio
indicado. Se puede indicar un filtro de bsqueda.
273
1etLast*ccessTime, devuelve la fecha y hora del ltimo acceso al directorio.
1etLast*ccessTime,tc, dem que el anterior, pero la fecha y hora en formato
UTC.
1etLast4riteTime, devuelve la fecha y hora de la ltima escritura realizada en
el directorio.
1etLast4riteTime,tc, como el anterior, pero usando fechas UTC.
1etLogicalDries, devuelve un array con los nombres de las unidades lgicas
en el formato: "<letra>:\".
1et+arent, devuelve el directorio de nivel superior del indicado.
(oe, mueve un fichero o directorio y su contenido a una nueva localizacin.
SetCreationTime, asigna la fecha y hora de creacin de un fichero o directorio.
SetCreationTime,tc, como el anterior, pero la fecha/hora es UTC.
SetCurrentDirectory, indica el directorio de trabajo de la aplicacin.
SetLast*ccessTime, asigna la fecha y hora del ltimo acceso.
SetLast*ccessTime,tc, como el anterior, pero la fecha/hora en formato UTC.
SetLast4riteTime, asigna la fecha y hora de la ltima escritura.
SetLast4riteTime,tc, como el anterior, pero usando la fecha y hora UTC.

Como hemos comentado, la clase DirectoryInfo siempre har referencia al directorio
utilizado para instanciarla, por tanto algunos de los mtodos de la clase Directory se
convierten en propiedades de esta clase y otros cambian de nombre para
adecuarlos mejor a la accin a realizar con ellos.
Por ejemplo, en la clase Directory tenemos el mtodo %&ists, que en DirectoryInfo
es una propiedad. De igual forma, el mtodo (oe de la clase Directory es el
mtodo (oeTo de DirectoryInfo.
En cuanto a los mtodos de Directory para obtener o asignar la fecha de creacin,
acceso, etc., en DirectoryInfo son propiedades de lectura/escritura.
Dicho esto, no vamos a relacionar todos estos miembros de DirectoryInfo, ya que
en la documentacin estn bien detallados y no nos resultar difcil de saber cmo
usarlos.
Lo que si queremos resaltar es que algunos de los mtodos de la clase
DirectoryInfo, concretamente 1etDirectories y 1et)iles, no devuelven un array de
tipo String, sino un array de objetos DirectoryInfo o )ileInfo respectivamente.
Tambin debemos indicar que la clase DirectoryInfo tiene ciertas propiedades, como
)ull$ame o $ame, que nos dan informacin del nombre de la ruta completa o del
nombre del directorio.
Y como nota final sobre Directory y DirectoryInfo, aclarar que el "filtro" (o pattern)
que podemos usar para filtrar los directorios o ficheros obtenidos con 1etDirectories
o 1et)iles solo pueden tener un filtro o especificacin, queremos aclarar este punto,
ya que en Visual Basic 6.0, si indicbamos un filtro en los controles File o Directory,
podamos indicar varios filtros separados por punto y coma (;), en las clases de
.NET esto no se puede hacer.
Para dejar claro estos puntos, veremos un ejemplo de cmo usar 1etDirectories y
1et)iles, con estas dos clases.
274
Im2orts S-stem
Im2orts S-stem/I0
Ho%!le Ho%!le
Const %ir1 As String = "DU?r!ebas"
S!b Hain()
Console/<rite'ine("#em2lo %e la clase Director-D")
claseDirector-()
Console/<rite'ine()
Console/<rite'ine("#em2lo %e la clase Director-In8oD")
claseDirector-In8o()
Console/<rite'ine()
4
Console/"ea%'ine()
n% S!b
S!b claseDirector-()
4 "ecorrer los s!b%irectorios %e !n %irectorio
Dim %irs() As String
%irs = Director-/;etDirectories(%ir1)
mostrar)icheros(%ir1, "O/tGt")
4 recorrer los 8icheros %e ca%a !no %e estos %irectorios
)or ach %ir As String In %irs
mostrar)icheros(%ir, "O/tGt")
AeGt
n% S!b
275
S!b mostrar)icheros(,-$al %ir As String, ,-$al 8iltro As
String)
Console/<rite'ine("'os 8icheros =0> %el %irectorioD =1>",
+
8iltro, %ir)
Dim 8ics() As String
8ics = Director-/;et)iles(%ir, 8iltro)
)or ach 8ic As String In 8ics
Console/<rite'ine(" )icheroD =0>", 8ic)
AeGt
n% S!b
S!b claseDirector-In8o()
Dim %i As AeJ Director-In8o(%ir1)
Dim %irs() As Director-In8o
%irs = %i/;etDirectories
mostrar)icheros(%i, "O/O")
)or ach %ir As Director-In8o In %irs
mostrar)icheros(%ir, "O/O")
AeGt
n% S!b
S!b mostrar)icheros(,-$al %ir As Director-In8o, ,-$al 8iltro
As String)
Console/<rite'ine("'os 8icheros =0> %el %irectorioD =1>",
+
8iltro, %ir/)!llAame)
Dim 8ics() As )ileIn8o
8ics = %ir/;et)iles(8iltro)
)or ach 8ic As )ileIn8o In 8ics
Console/<rite'ine(" )icheroD =0>", 8ic/Aame)
276
AeGt
n% S!b
n% Ho%!le


'as clases <ile y <ile-nfo
Al igual que ocurre con las clases para manejar los directorios, tenemos dos clases
diferentes para manejar los ficheros, una de ellas ()ile) todos los mtodos que tiene
son estticos, por tanto podemos usarlos directamente, sin crear una nueva
instancia de la clase. Por otro lado la clase )ileInfo es una clase de la que tenemos
que crear un nuevo objeto para poder usarla, al crear ese objeto (o instancia),
tenemos que indicar el fichero al que har referencia, ese fichero no tiene porqu
existir previamente.
En el siguiente cdigo podemos ver cmo usar estas dos clases.
Im2orts S-stem
Im2orts S-stem/I0
Ho%!le Ho%!le1
Const 8ic1 As String = "DU?r!ebasU?r!eba/tGt"
Const 8ic2 As String = "DU?r!ebasUS!bDirU?r!eba3/tGt"
S!b Hain()
Console/<rite'ine("#em2lo %e la clase )ileD")
clase)ile()
Console/<rite'ine()
Console/<rite'ine("#em2lo %e la clase )ileIn8oD")
clase)ileIn8o()
Console/<rite'ine()
4
Console/"ea%'ine()
277
n% S!b
S!b clase)ile()
4 com2robar si el 8ichero eGiste
I8 )ile/Gists(8ic1) 1hen
Console/<rite'ine("l 8ichero 4=0>4 SI eGiste", 8ic1)
Console/<rite'ine(")echa creaciSnD =0>",
)ile/;etCreation1ime(8ic1))
lse
Console/<rite'ine("l 8ichero 4=0>4 A0 eGiste", 8ic1)
n% I8
n% S!b
S!b clase)ileIn8o()
Dim 8i As AeJ )ileIn8o(8ic2)
4
4 Com2robar si eGiste el 8icheroD
I8 8i/Gists 1hen
Console/<rite'ine("l 8ichero 4=0>4 SI eGiste", 8ic2)
Console/<rite'ine(")echa creaciSnD =0>",
8i/Creation1ime)
agregar1eGto(8i)
lse
Console/<rite'ine("l 8ichero 4=0>4 A0 eGiste", 8ic2)
4 lo creamos
8i/Create()
n% I8
n% S!b
S!b agregar1eGto(,-$al 8i As )ileIn8o)
278
Dim 8s As Stream<riter
8s = 8i/Create1eGt
8s/<rite'ine("Hola, H!n%o")
8s/)l!sh()
8s/Close()
4
8i/"e8resh()
Console/<rite'ine("1amaTo D =0>", 8i/'ength)
n% S!b
n% Ho%!le

Cifrar y descifrar un fic%ero usando (ile o (ileInfo
En los sistemas operativos Windows XP y Windows 2003, al mostrar el cuadro de
dilogo de las propiedades avanzadas de un fichero, nos permite cifrarlo, de forma
que el usuario actual slo tenga acceso al contenido del mismo.
Fi'ura 0<.0<.0$ Pindos L82200< nos permite cifrar un fic?ero
Tanto la clase File como )ileInfo tienen mtodos para realizar esta operacin, as
como la inversa: descifrarlo. Cuando ciframos un fichero, solo el usuario actual
podr acceder a su contenido (y el resto de administradores), la forma de hacerlo
es bien simple: solo tenemos que llamar al mtodo %ncrypt o Decrypt para cifrarlo o
279
descifrarlo. Cuando est cifrado, el nombre del fichero se mostrar en un color
diferente al del resto de ficheros (de forma predeterminada en verde).
Esta forma de cifrado es diferente a la que vimos en la leccin anterior, ya que si
ciframos el contenido de un fichero de forma "manual", siempre estar cifrado,
independientemente de quin acceda al fichero.
Cuando utilizamos los mtodos para cifrar o descifrar un fichero, no recibiremos
ninguna excepcin si aplicamos el mtodo de cifrar sobre un fichero ya cifrado. Pero
si queremos saber si un determinado fichero est o no cifrado, lo podemos
averiguar mediante la propiedad *ttribute de la clase )ileInfo, particularmente
comprobando si tiene activado el atributo )ile*ttributes.%ncrypted.
En el siguiente cdigo tenemos ejemplos de cmo usar las clases )ile y )ileInfo para
comprobar si un fichero ya est cifrado, en cuyo caso lo desciframos, y si resulta
que no est cifrado, lo ciframos.
Im2orts S-stem
Im2orts S-stem/I0
Ho%!le Ho%!le1
Const 8ic1 As String = "DU?r!ebasU?r!eba/tGt"

S!b Hain()
ci8ra%o)ile(8ic1)
Console/<rite'ine()
ci8ra%o)ileIn8o(8ic2)
Console/<rite'ine()
4
Console/"ea%'ine()
n% S!b
4 Ci8rar V Desci8rar 8icheros
4 - com2robar si -a est6n ci8ra%os///
S!b ci8ra%o)ile(,-$al 8ichero As String)
4 com2robar si est6 ci8ra%o,
280
Dim atrib As )ileAttrib!tes
atrib = )ile/;etAttrib!tes(8ichero)
I8 (atrib An% )ileAttrib!tes/ncr-2te%) =
)ileAttrib!tes/ncr-2te% 1hen
Console/<rite'ine("l 8ichero =0> -a estaba ci8ra%o/",
8ichero)
)ile/Decr-2t(8ichero)
lse
)ile/ncr-2t(8ichero)
Console/<rite'ine("l 8ichero =0> no estaba ci8ra%o/",
8ichero)
n% I8
n% S!b
S!b ci8ra%o)ileIn8o(,-$al 8ichero As String)
4 com2robar si est6 ci8ra%o,
Dim 8i As AeJ )ileIn8o(8ichero)
Dim atrib As )ileAttrib!tes
atrib = 8i/Attrib!tes
I8 (atrib An% )ileAttrib!tes/ncr-2te%) =
)ileAttrib!tes/ncr-2te% 1hen
Console/<rite'ine("l 8ichero =0> -a estaba ci8ra%o/",
8i/)!llAame)
8i/Decr-2t()
lse
8i/ncr-2t()
Console/<rite'ine("l 8ichero =0> no estaba ci8ra%o/",
8i/)!llAame)
n% I8
n% S!b
n% Ho%!le

281

Abrir fic%eros para a"re"ar o leer el contenido
Estas dos clases de manipulacin de ficheros exponen una serie de mtodos que
nos permiten abrir el fichero al que hace referencia la clase para leer el contenido
del mismo o para escribir en l.
Dependiendo del mtodo usado, ste devolver un objeto de tipo )ileStream o
Stream'eader o Stream4riter. Esto nos permite de una forma fcil poder acceder al
contenido que tiene sin necesidad de usar otros constructores. Lo que si debemos
tener en cuenta es que en el caso de que leamos o escribamos texto, ste se
guardar usando la codificacin UTF-8, por tanto si queremos usar otro tipo de
codificacin, tendremos que abrirlos usando los constructores correspondientes,
normalmente los de las clases Stream'eader y Stream4riter. De estas dos clases
nos ocuparemos en el siguiente captulo.
Veamos un par de ejemplos que nos permitan leer el contenido o agregar nuevo
texto a los ficheros.
Im2orts S-stem
Im2orts S-stem/I0
Ho%!le Ho%!le1
Const 8ic3 As String = "DU?r!ebasU?r!eba./tGt"
Const 8ic. As String = "DU?r!ebasUS!bDirU?r!eba./tGt"
S!b Hain()
abrir)ile(8ic3)
Console/<rite'ine()
abrir)ileIn8o(8ic.)
Console/<rite'ine()
4
Console/"ea%'ine()
n% S!b
4 Abrir 8icheros 2ara leer el conteni%o o escribir en Rl
S!b abrir)ile(,-$al 8ichero As String)
282
I8 )ile/Gists(8ichero) 1hen
Dim 8s As )ileStream = )ile/02en"ea%(8ichero)
Dim enc As AeJ S-stem/1eGt/F1)Xnco%ing()
Dim %atos(102.) As ,-te
8s/"ea%(%atos, 0, %atos/'ength)
8s/Close()
Dim s As String = enc/;etString(%atos, 0,
%atos/'ength)
Console/<rite'ine("l conteni%o %eD =0>=2> esD=2>=1>",
+
8ichero, s, 5bCr'8)
lse
Console/<rite'ine(";!ar%an%o algo en el 8ichero =0>",
8ichero)
Dim 8s As )ileStream = )ile/02en<rite(8ichero)
Dim enc As AeJ S-stem/1eGt/F1)Xnco%ing()
Dim %atos() As ,-te = enc/;et,-tes("7Hola b-tesY")
8s/<rite(%atos, 0, %atos/'ength)
8s/Close()
n% I8
n% S!b
S!b abrir)ileIn8o(,-$al 8ichero As String)
Dim 8i As AeJ )ileIn8o(8ichero)
I8 8i/Gists 1hen
4 abrir el 8ichero como teGto - leemos el conteni%o
Dim sr As Stream"ea%er = 8i/02en1eGt
Dim s As String = sr/"ea%1on%
Console/<rite'ine("l conteni%o %eD =0>=2> esD=2>=1>",
+
8ichero, s, 5bCr'8)
283
lse
Console/<rite'ine(";!ar%an%o algo en el 8ichero =0>",
8ichero)
Dim sJ As AeJ Stream<riter(8i/02en<rite)
sJ/<rite'ine("Hello b-tesY")
sJ/Close()
n% I8
n% S!b
n% Ho%!le

En el mtodo a#rirFile utilizamos la clase )ile para abrir, leer y escribir en un
fichero. En este caso estamos usando un objeto del tipo )ileStream para acceder al
contenido de dicho fichero, como sabemos, esta clase solo trabaja con bytes, por
tanto si queremos leer el contenido del mismo, debemos hacerlo mediante un array
de bytes y para mostrar en formato texto ese contenido, tenemos que aplicarle la
codificacin correspondiente para extraer el contenido en forma de una cadena. Lo
mismo hacemos para guardar una cadena en el fichero, (en caso de que no exista
previamente).
En el mtodo a#rirFileInfo, en lugar de crear un objeto )ileStream para acceder al
contenido, usamos uno del tipo Stream'eader, ya que esta clase si que nos
devolver una cadena sin necesidad de hacer conversiones extras. Lo mismo ocurre
a la hora de escribir algo en el fichero, aunque en esta ocasin utilizamos un objeto
del tipo Stream4riter.
En el primer caso, cuando leemos el contenido, utilizamos el mtodo OpenTe&t, el
cual devuelve un objeto del tipo Stream'eader. Por otra parte, cuando queremos
guardar texto, lo que hacemos es pasarle al constructor de la clase Stream4riter el
objeto )ileStream devuelto por el mtodo Open4rite.

Nota3
Como hemos podido comprobar, cuando tratamos con las clases
DirectoryInfo o FileInfo, siempre estamos tratando con instancias que
pueden ser diferentes y por tanto mltiples, esas instancias siempre
manejan el directorio o fichero usado en el constructor, por tanto, ser
preferible usar estas clases cuando tengamos que hacer varias
operaciones sobre el mismo directorio o fichero.
Por otro lado, si solo queremos hacer pocas operaciones, podemos
usar las clases Directory o File, ya que no necesitaremos crear un
objeto en memoria para hacer las tareas que necesitemos hacer.

284


%anipular cadenas relacionadas con fic#eros y directorios usando
,at#
La clase +at" es una clase especial, en la que todos los mtodos son estticos, por
tanto para usarla no necesitamos crear una instancia. Lo de "especial" es porque
esta clase realmente no realiza ninguna accin "fsica" sobre los directorios (o
ficheros), simplemente nos permite manipular los nombres de esos directorios o
ficheros.
Por ejemplo, podemos usar esta clase para obtener informacin sobre un fichero,
como el nombre completo, el nombre del directorio o la extensin.
En el siguiente cdigo vemos cmo usar algunos de esos mtodos:
Const 8ic1 As String = "DU?r!ebasU?r!eba/tGt"
S!b clase?ath()
Console/<rite'ine("Aombre com2letoD =0>", 8ic1)
Console/<rite'ine("l nombreD =0>", ?ath/;et)ileAame(8ic1))
Console/<rite'ine("Sin eGtensiSnD =0>",
?ath/;et)ileAame<itho!tGtension(8ic1))
Console/<rite'ine("'a eGtensiSnD =0>",
?ath/;etGtension(8ic1))
Console/<rite'ine("l %irectorioD =0>",
?ath/;etDirector-Aame(8ic1))
n% S!b


Nota3
Debido a que la clase Path solo maneja cadenas, podemos usar los
mtodos de esta clase con nombres de ficheros o directorios que no
existen, y por tanto, cualquier cambio que hagamos en esos
parmetros, no afectarn a ningn fichero ni directorio.


285
Debido a que los ensamblados de .NET podemos usarlos con diferentes sistemas
operativos (al menos en teora), esta clase proporciona ciertas propiedades que nos
permiten averiguar los caracteres especiales de cada sistema, por ejemplo para
saber el separador usado por los directorios.

Con esta clase tambin podemos crear ficheros con nombres temporales, de forma
que nos aseguremos de que no habr otro fichero "temporal" con el mismo nombre.
Igualmente, por medio del mtodo 1etTemp+at" podemos averiguar el directorio
temporal del sistema.
Incluso podemos generar nombres aleatorios "seguros" para ficheros o directorios
mediante el mtodo 1et'andom)ile$ame.
Veamos un ejemplo para generar estos nombres temporales y aleatorios:
Dim %ir As String
%ir = ?ath/;et1em2?ath()
Console/<rite'ine("Directorio tem2oralD =0>", %ir)
Dim 8ic As String
8ic = ?ath/;et1em2)ileAame()
Console/<rite'ine(")ichero tem2oralD =0>", 8ic)
4
8ic = ?ath/;et"an%om)ileAame()
Console/<rite'ine(")ichero ran%omD =0>", 8ic)

En los dos primeros casos, se usa el directorio )TEM8) del sistema. Y en el caso
del fichero temporal, la extensin es .tmp
En el nombre aleatorio, tanto el nombre como la extensin estn formados por
caracteres "imprimibles" aleatorios.

286

*as clases para leer o escri#ir en los streams
Las clases que podemos usar para leer o escribir en los streams, (y por extensin
en los ficheros a los que apuntan esos streams), son:
Binary'eader, lee tipos primitivos o cadenas codificadas desde un )ileStream.
Binary4riter, escribe tipos primitivos o cadenas codificadas en un )ileStream.
Stream'eader, lee caracteres desde un )ileStream, usando codificacin para
convertir los caracteres a/desde bytes.
Stream4riter, escribe caracteres a un )ileStream, usando codificacin para
convertir los caracteres en bytes.
String'eader, lee caracteres desde un String. La salida puede ser a un stream
en cualquier codificacin o a una cadena.
String4riter, escribe caracteres a un String. Al igual que String'eader, la
salida puede ser a un stream usando cualquier codificacin o a una cadena.

Te&t'eader, es la clase abstracta base para Stream'eader y String'eader.
Te&t4riter, es la case abstracta base para Stream4riter y String4riter.


287
'as clases StreamEeader y StreamJriter
Aunque ya hemos utilizado algunas de estas clases en los ejemplos que hemos
estado viendo, nos vamos a centrar en las dos que con ms asiduidad usaremos:
Stream'eader y Stream4riter, aunque solo trataremos algunos temas, ya que en
lneas generales, ya "deberamos" saber cmo usarlas.

Estas dos clases las podemos crear directamente, indicando el fichero al que
accederemos o bien, podemos usar el valor devuelto por alguna otra clase o mtodo
de las clases )ile o )ileInfo.

La codificacin de los fic%eros de *;$
En lo que resta de este captulo nos centraremos en los formatos de codificacin
usados con estas dos clases, y por regla general con los ficheros de .NET.
La principal ventaja de estas clases es que nos permiten acceder al contenido de los
ficheros en modo texto, que es lo que necesitaremos en la mayora de los casos.
Tambin podremos indicar en el constructor de estas clases la codificacin a usar.
Como ya hemos comentado en otras ocasiones, por defecto esa codificacin es UTF-
8, es decir caracteres Unicode de 8 bits. Pero si queremos leer y escribir ficheros
que sean compatibles con otras aplicaciones de Windows, por ejemplo, nuestras
aplicaciones de Visual Basic 6.0, deberamos usar la codificacin ANSI, que es la
predeterminada de los sistemas Windows. De esta forma podremos leer y escribir
caracteres "raros" como la letra ee o las vocales con tildes.
Para indicar la codificacin a usar, lo tendremos que indicar como parmetro del
constructor, por ejemplo, para abrir un fichero con la codificacin predeterminada de
Windows, lo haremos de esta forma:
Dim sr As AeJ Stream"ea%er(8ic1, nco%ing/De8a!lt)
Es decir, usamos la codificacin Default, que es la predeterminada de Windows.

Nota3
Si no indicamos la codificacin que queremos usar, sta ser UTF-8.
Pero debemos tener en cuenta que esta codificacin solamente leer
correctamente los ficheros que se hayan guardado previamente
usando esa misma codificacin, por tanto, si queremos leer ficheros
creados con VB6, no deberamos usar UTF-8, (Encoding.UTF8), sino
Encoding.Default.

288
Algunos tipos de ficheros (segn la codificacin usada), guardarn al principio del
mismo una marca: BOM (Byte Order (ar6) indicando la codificacin usada para
escribir en ellos. El propio .NET puede usar dicha marca a la hora de leer en los
ficheros, para que as lo haga, podemos indicarlo en el constructor de la clase
Stream'eader:
Fi'ura 0<.0<.02 /etectar autom.ticamente la codificacin usada
Aunque esta deteccin automtica solo funcionar con los tipos de ficheros que
guardan dicha informacin, que son los tipos: UTF-8, UTF-16 y UTF-32, de estos
dos ltimos existen dos marcas segn se utilice "big-endian" o "little-endian", es
decir, si el byte ms significativo est al principio o al final respectivamente. Estas
marcas, conocidas en .NET como "prembulos", se pueden averiguar tambin por
medio del mtodo 1et+reamble de la clase %ncoding.
En la siguiente tabla podemos ver los valores hexadecimales de las marcas usadas
en los ficheros.
Codificacin
Nmero de
bytes
Secuencia de bytes
(hex)
UTF-8 3 EF BB BF
UTF-16 Little-Endian 2 FF FE
UTF-16 Big-Endian 2 FE FF
UTF-32 Little-Endian 4 00 00 FF FE
UTF-32 Big-Endian 4 00 00 FE FF
Ta#la 0<.0<.0$ Marcas 9B7M: de los fic?eros GTF

Cuando leemos la informacin de un fichero abierto por medio de Stream'eader,
podemos hacerlo lnea a lnea o bien todo el contenido de una sola vez. Como vimos
en la leccin de los streams, podemos usar el mtodo 'eadLine o 'eadTo%nd para
realizar estas dos operaciones de lectura.

Al usar la clase Stream4riter, tambin podemos indicar la codificacin a usar para
guardar el texto del fichero:
289
Dim sJ As AeJ Stream<riter(8ic2, )alse, nco%ing/De8a!lt)
El segundo parmetro del constructor lo usaremos para indicar si queremos aadir
texto al contenido del fichero (True) o simplemente queremos sobrescribirlo,
()alse), de forma que cualquier contenido anterior desaparezca.

Como recomendacin final, y siguiendo con el tema de la codificacin, (que aunque
parezca algo "trivial" a muchos usuarios les da algn que otro dolor de cabeza),
decir que debemos tener precaucin a la hora de elegir la ms adecuada.
Si queremos que los ficheros que manejemos con nuestra aplicacin de Visual
Basic 2005 sean "compatibles" con los de VB6, deberamos usar la
codificacin %ncoding.Default.
Si los ficheros solo se usarn desde aplicaciones de .NET, podemos usar la
codificacin predeterminada, es decir: UTF-8.
Si vamos a guardar ficheros XML, deberamos usar siempre codificacin UTF-
8, que es la predeterminada para ese formato de ficheros.


El o#(eto M%
Entre los objetivos de este curso no est hablar del objeto (y y de los objetos que
contiene, los cuales nos facilitan un acceso rpido a la mayora de recursos con los
que habitualmente trabajaremos en nuestras aplicaciones.
290
Pero no nos gustara dejar un "mal sabor de boca", el cual se quedara si no
hablramos, aunque sea un poco de este objeto.
Tambin es cierto que el objeto (y (y el resto de objetos que lo compone) ser uno
de los que con ms frecuencia encontraremos documentacin y ejemplos, tanto en
la Web como en la propia documentacin de Visual Basic 2005, por tanto
quisiramos que el lector no deje de leer sobre este objeto, ya que en muchas
ocasiones nos ayudar a hacer muchas de las tareas habituales en cualquier
aplicacin, e incluso los desarrolladores de VB6 encontrarn muchos de los objetos
a los que estn acostumbrados a utilizar, como el objeto *pp o la forma de acceder
a la coleccin de los formularios cargados en la memoria.

El obeto %y.Computer.<ileSystem
En cuanto a lo que respecta al sistema de archivos, la mayora de la funcionalidad
est incluida en el objeto (y.Computer.)ileSystem. Si bien, debemos aclarar que
esos objetos o propiedades, realmente son una especie de acceso directo a las
clases del propio .NET Framework, y esa es la excusa de no haber tratado este
objeto con ms profundidad, ya que si sabemos manejar el resto de clases de .NET,
sabremos trabajar con el objeto (y.
Entre las propiedades del objeto (y.Computer.)ileSystem, podemos encontrar
muchos de los mtodos que exponen las clases )ile y Directory, aunque estos
mtodos tendrn nombres diferentes, por ejemplo, en lugar de tener un mtodo
%&ists, nos encontramos con uno para averiguar si existe un directorio:
Directory%&ists, y otro para averiguar si existe un fichero: )ile%&ists.

Tambin quisiramos resaltar dos mtodos que pueden sernos de bastante utilidad
cuando estemos buscando texto en los ficheros o cuando queramos abrir un fichero
con una estructura determinada, nos estamos refiriendo a los mtodos: )indIn)iles
y OpenTe&t)ield+arse respectivamente.

#uscar te5to en fic%eros con (indIn(iles
)indIn)iles devuelve una coleccin "generic" de tipo String y de solo lectura con los
ficheros que contienen el texto indicado.
En el siguiente ejemplo buscamos ficheros que contenga el texto "hola", se ignore
las maysculas y minsculas y se haga la bsqueda tambin en los subdirectorios:
Dim list As S-stem/Collections/0b#ectHo%el/"ea%0nl-Collection(08
String)
4 ,!scar teGto en los 8icheros/
list = H-/Com2!ter/)ileS-stem/)in%In)iles( +
291
"DU?r!ebas", "hola", +
1r!e, )ileI0/Search02tion/SearchAllS!bDirectories)
4 Hostrar los 8icheros con el teGto in%ica%o/
)or ach name As String In list
Console/<rite'ine(name)
AeGt

5aminar el contenido de un fic%ero con formato con
:pen$e5t(ield9arse
En el siguiente ejemplo vamos a abrir un fichero con una estructura, realmente
delimitado con tabuladores, leeremos el contenido y lo mostraremos examinando
cada uno de los campos.
En este ejemplo, podramos llamar al mtodo Te&t+arser de la siguiente forma:
teGt?arser("DU?r!ebasU?r!eba 2arse/tGt", 5b1ab)
S!b teGt?arser(,-$al 8ic As String, ,-$al se2 As String)
4 Creamos el "2arser"/
Dim rea%er As )ileI0/1eGt)iel%?arser
rea%er = H-/Com2!ter/)ileS-stem/02en1eGt)iel%?arser(8ic)
4 'e in%icamos I!e b!scaremos %elimita%ores/
rea%er/1eGt)iel%1-2e = )ileI0/)iel%1-2e/Delimite%
4 Fn arra- con los %elimita%ores/
rea%er/Delimiters = AeJ String() =se2>
Dim 8ila() As String
4 Hientras ha-a %atos///
<hile Aot rea%er/n%08Data
1r-
4 'eemos to%os los cam2os/
8ila = rea%er/"ea%)iel%s()
Console/<rite'ine("'os cam2os %e la 8ila sonD")
292
4 'os mostramos/
)or ach cam2o As String In 8ila
Console/<rite("=0>, ", cam2o)
AeGt
Console/<rite'ine()
Catch eG As Gce2tion
Console/<rite'ine("rrorD " P eG/Hessage)
n% 1r-
n% <hile
n% S!b


Introduccin
Esta es otra de las reas con la que los desarrolladores de VB6 se vern
beneficiados, al menos si nuestra intencin es la acceder a la red de redes:
Internet.
Aunque tambin tendremos clases para interactuar con nuestra red local o
empresarial, adems de clases para comunicacin por "sockets" y acceso a FTP, etc.
293
Las mayora de las clases que necesitemos para acceder a la red, las encontraremos
en el espacio de nombres System.$et.


4cceso a Internet
System.Net: 'as clases para acceder a la red
o Las clases de System.Net
o Acceder a una pgina Web
o Acceder a un servidor FTP
o Acceso rpido a la red con My.Computer.Network
Averiguar si tenemos red disponible
Hacer Ping a un equipo
Bajar un fichero desde una direccin Web

'as clases de System.Net
En este espacio de nombres tenemos una gran cantidad de clases, entre las que
podemos destacar las siguientes.
*ut"entication(anager, administra los mdulos de autenticacin durante el
proceso de autenticacin del cliente.
*ut"ori.ation, contiene un mensaje de autenticacin de un servidor de
Internet.
Coo6ie, proporciona mtodos y propiedades para administrar los cookies.
CredentialCac"e, proporciona almacenamiento para mltiples credenciales.
Dns, proporciona funcionalidad simple para resolucin de nombres de
dominios.
Dns+ermission, controla los permisos de acceso a servidores DNS en la red.
%nd+oint, clase abstracta que identifica una direccin de red.
)ile4eb'e9uest, proporciona una implementacin del sistema de archivos de
la clase 4eb'e9uest.
)ile4eb'esponse, proporciona una implementacin del sistema de archivos
de la clase 4eb'esponse.
)tp4eb'e9uest, implementa un cliente FTP.
)tp4eb'esponse, encapsula una respuesta desde una peticin a un servidor
FTP.
7ttpListener, proporciona un protocolo de escucha HTTP simple.
7ttpListenerBasicIdentity, proporciona la identidad para la clase 7ttpListener.
7ttpListenerConte&t, proporciona acceso a las peticiones y respuestas
utilizadas por la clase 7ttpListener.
7ttpListener'e9uest, describe una peticin HTTP a un objeto 7ttpListener.
7ttpListener'esponse, representa una respuesta a una peticin administrada
por un objeto 7ttpListener.
294
7ttp#ersion, define las versiones HTTP soportadas por las clases
7ttp4eb'e9uest y 7ttp4eb'esponse.
7ttp4eb'e9uest, proporciona una implementacin HTTP especfica de la clase
4eb'e9uest.
7ttp4eb'esponse, proporciona una implementacin HTTP especfica de la
clase 4eb'esponse.
I+*ddress, proporciona una direccin IP (Internet +rotocol).
I+%nd+oint, representa un punto final de red como una direccin IP y un
nmero de puerto.
I+7ost%ntry, proporciona una clase contenedora para la informacin de
direccin de host de Internet.
$et!or6Credential, proporciona credenciales para autenticacin basada en
contrasea.
Serice+oint, proporciona administracin de conexiones para las conexiones
HTTP.
Serice+oint(anager, administra la coleccin de objetos Serice+oint.
Soc6et*ddress, almacena informacin serializada de las clases derivadas de
EndPoint.
Soc6et+ermission, controla los derechos para realizar o aceptar conexiones en
una direccin de transporte.
4ebClient, proporciona mtodos comunes para enviar o recibir datos desde
un recurso identificado por una URI (,niform 'esource Identifier).
4eb+ermission, controla los derechos de acceso a un recurso HTTP de
Internet.
4eb+ro&y, contiene la configuracin del proxy HTTP de la clase 4eb'e9uest.
4eb'e9uest, realiza una peticin a una URI.
4eb'e9uest(et"ods, clase contenedora para las clases
4eb'e9uest(et"ods.)tp, 4eb'e9uest(et"ods.)ile, y
4eb'e9uest(et"ods.7ttp.
4eb'e9uest(et"ods.)ile, representa los tipos del protocolo de fichero que se
pueden usar con una peticin FILE.
4eb'e9uest(et"ods.)tp, representa los tipos del protocolo FTP que se
pueden usar con una peticin FTP.
4eb'e9uest(et"ods.7ttp, representa los tipos del protocolo HTTP que se
pueden usar con una peticin HTTP.
4eb'esponse, proporciona una respuesta desde una URI.


Acceder a una p&gina Jeb
Empezaremos viendo cmo acceder a una pgina Web. Para este tipo de acceso
vamos a usar la clase abstracta 4eb'e9uest y de paso algunas otras clases como
4eb'esponse y otras para manejar el stream recibido con el contenido de la pgina
solicitada.
Veamos un pequeo ejemplo, (basado y simplificado de uno de la documentacin),
para hacerlo:
295
S!b leer?agina<eb(,-$al laFrl As String)
4 Cear la solicit!% %e la F"'/
Dim reI!est As <eb"eI!est = <eb"eI!est/Create(laFrl)
4 0btener la res2!esta/
Dim res2onse As <eb"es2onse = reI!est/;et"es2onse()
4 Abrir el stream %e la res2!esta recibi%a/
Dim rea%er As AeJ Stream"ea%er(res2onse/;et"es2onseStream())
4 'eer el conteni%o/
Dim res As String = rea%er/"ea%1on%()
4 Hostrarlo/
Console/<rite'ine(res)
4 Cerrar los streams abiertos/
rea%er/Close()
res2onse/Close()
n% S!b
Si la direccin que estamos solicitando es una pgina "activa", el valor que
recibiremos es el cdigo "cliente", es decir, el cdigo que se enviar al navegador.
Si necesitamos hacer algunas peticiones ms especficas o necesitamos obtener
alguna otra informacin podemos usar un objeto del tipo 7ttp4eb'e9uest el cual
est basado en la clase 4eb'e9uest, pero que la ampla para ofrecer otros tipos de
informacin y acciones ms adecuadas a una peticin HTTP.
La forma de usar esta clase sera igual que 4eb'e9uest, adems de que la
documentacin recomienda usar el mtodo Create de 4eb'e9uest para crear una
nueva instancia de 7ttp4ebre9uest.
En el siguiente ejemplo, le indicamos que estamos usando un navegador desde un
"Smartphone":
S!b leer?agina<eb2(,-$al laFrl As String)
4 Cear la solicit!% %e la F"'/
Dim h"eI!est As Htt2<eb"eI!est = +
C1-2e(<eb"eI!est/Create(laFrl), Htt2<eb"eI!est)
4 2ara I!e lo %e5!el5a como si acce%iRramos con !n Smart2hone
h"eI!est/FserAgent = +
296
"Ho&illaV./0 (com2atible[ HSI ./01[ <in%oJs C[
Smart2hone[ 1N6G220)"
4 0btener la res2!esta - abrir el stream %e la res2!esta
recibi%a/
Dim rea%er As AeJ
Stream"ea%er(h"eI!est/;et"es2onse/;et"es2onseStream)
Dim res As String = rea%er/"ea%1on%()
4 Hostrarlo/
Console/<rite'ine(res)
4 Cerrar el stream abierto/
rea%er/Close()
n% S!b


Acceder a un servidor <T,
Por medio de la clase )tp4eb'e9uest podemos acceder a una direccin FTP de
forma bastante fcil, como es habitual en este tipo de clases, este objeto se crea
mediante el mtodo compartido Create, al que le debemos pasar la direccin FTP a
la que queremos acceder.
Debido a que los sitios FTP pueden estar protegidos por contrasea, es posible que
necesitemos asignar la propiedad Credentials de este objeto, esto lo podemos hacer
asignando el objeto creado a partir de la clase $et!or6Credential.
Los distintos comandos que necesitemos enviar al FTP lo haremos mediante la
propiedad (et"od.
En el siguiente ejemplo utilizamos la clase )tp4eb'e9uest para listar el contenido
de un directorio FTP pblico.
S!b Hain()
listar)1?("8t2D"VV8t2/re%iris/es", "anonimo!s\na%ie/com", "")
4
Console/"ea%'ine()
n% S!b
S!b listar)1?(,-$al %ir As String, ,-$al !ser As String, ,-$al
2ass As String)
297
Dim %ir)t2 As )t2<eb"eI!est = C1-2e()t2<eb"eI!est/Create(%ir),
)t2<eb"eI!est)
Dim cr As AeJ AetJorQCre%ential(!ser, 2ass)
%ir)t2/Cre%entials = cr
%ir)t2/Hetho% = "'IS1"
Dim rea%er As AeJ
Stream"ea%er(%ir)t2/;et"es2onse()/;et"es2onseStream())
Dim res As String = rea%er/"ea%1on%()
4 Hostrarlo/
Console/<rite'ine(res)
4 Cerrar el stream abierto/
rea%er/Close()
n% S!b


Acceso r&pido a la red con %y.Computer.NetForI
El objeto (y tambin contiene objetos con los que podemos acceder a ciertas
caractersticas de la red, en particular mediante el objeto (y.Computer.$et!or6
tenemos acceso a una propiedad y tres mtodos con los que podemos hacer lo
siguiente:
Is*aillable, esta propiedad nos permite saber si la red est disponible.
+ing, con este mtodo podemos hacer un "ping" a un equipo remoto.
Do!nload)ile, nos permite bajar un fichero desde una direccin Web.
,pload)ile, nos permite enviar un fichero a una direccin Web.
En el siguiente cdigo tenemos ejemplos de estos mtodos y propiedades:
I8 H-/Com2!ter/AetJorQ/IsA5ailable = 1r!e 1hen
Console/<rite'ine("l or%ena%or est6 conecta%o/")
lse
Console/<rite'ine("l or%ena%or no est6 conecta%o/")
n% I8
4
298
I8 H-/Com2!ter/AetJorQ/?ing("1E2/16X/1/26") 1hen
Console/<rite'ine("l eI!i2o est6 acti5o/")
lse
Console/<rite'ine("Se ha sobre2asa%o el tiem2o %e es2era/")
n% I8
4
Dim 8icDest As String = "DU?r!ebasUrobots/tGt"
H-/Com2!ter/AetJorQ/DoJnloa%)ile( +
"htt2D"VVJJJ/elg!ille/in8oVrobots/tGt", +
8icDest)
4
I8 H-/Com2!ter/)ileS-stem/)ileGists(8icDest) 1hen
Console/<rite'ine("l 8ichero se ha ba#a%o")
lse
Console/<rite'ine("l 8ichero no se ha ba#a%o")
n% I8
4--ES7 4 /4T7S

299
%(dulo B ? -ntroducci(n
En este mdulo, aprenderemos a trabajar con datos y fuentes de datos en Visual Basic
2005.
Sin lugar a dudas, la mayora de los desarrolladores que vienen de Visual Basic 6, es
aqu dnde encuentran las mayores dificultades de migracin, ya que el modelo de
acceso a datos ha variado bastante y adecuarse a los cambios, es lo que a buen
seguro representa el mayor esfuerzo en la curva de aprendizaje de Visual Basic 2005.
An as y con todo esto, no se preocupa, no est solo o sola.
En este tutorial, encontrar las cosas ms importantes que debe saber, para trabajar
con fuentes de datos con Visual Basic 2005.
De esta manera, aprender en poco tiempo, a encontrarse cmodo en el nuevo
entorno de clases de ADO.NET y podr as, sacar el mximo provecho a sus
desarrollos.
Becomendacin3
Se acuerda de ADO, DAO, etc.?
,na recomendaci<n 9ue le "ago para seguir esta importantIsima parte
del tutorial es pasar p@gina a *DO3 D*O y otros accesos a datos 9ue
us@bamos en #isual Basic G.
$o intente comparar *DO.$%T con los anteriores ni intente tampoco
usar los anteriores con #isual Basic 2BBC.
Debemos pasar p@gina y olidarnos por completo de lo 9ue sabemos
"asta a"ora para centrarnos en los nueos "@bitos3 de lo contrario3 lo
;nico 9ue conseguir@ ser@ perder el tiempo y complicar m@s su
aprendi.aje li@ndose.
Productos Visual Studio Express
Las partes que forman parte de este mdulo son las siguientes:
Cap!tulo @

Descripcin de ADO.NET
Cap!tulo 1

Acceso conectado a bases de datos
Cap!tulo A

Acceso desconectado: DataSets y DataAdapters
Cap!tulo B

DataSets tipados
300
Cap!tulo 3

Enlace a formularios

-ntroducci(n
Si usted ha tenido amplia experiencia trabajando con ADO y Visual Basic 6, debe saber
que ADO.NET no es ADO, de hecho, ADO.NET plantea tal cantidad de cambios, que lo
mejor que puede hacer en el caso de tener amplia experiencia en ADO, es olvidarse de
ste y aprender lo que ADO.NET le ofrece.
Las comparaciones son humanas, y seguro que a medida que avancemos en nuestro
aprendizaje con ADO.NET, har alguna en bastantes ocasiones. De hecho, hay
estrechas similitudes entre ADO y ADO.NET, pero mi sugerencia, es tratar en lo
posible, de no prestar atencin a esto.
A continuacin veremos todo lo que debe saber sobre ADO.NET para crear aplicaciones
que accedan a fuentes de datos desde Visual Basic 2005.
Comprobar que ahora, es incluso mucho ms fcil y rpido, si bien, es necesario
conocer el modelo con el que se trabaja para poder saber lo que hacemos en un
momento dado.
%(dulo B ? Cap!tulo @

1. Acercndonos a ADO.NET
2. System.Data
3. Los proveedores de acceso a datos
4. El concepto DataBinding
301
5. Otras consideraciones

%(dulo B ? Cap!tulo @
@. Acerc&ndonos a A"$.NET
ADO.NET ha sufrido a lo largo de los ltimos aos diferentes mejoras y
actualizaciones, desde que .NET apareci.
El resumen de las diferentes versiones de ADO.NET podra quedar de la siguiente
forma.
ADO.NET 1.0 apareci con Microsoft .NET Framework 1.0. Posteriormente, ADO.NET
1.1 sufri una pequeas y casi inapreciables actualizaciones con la aparicin de
Microsoft .NET Framework 1.1. En el caso del entorno Visual Basic 2005 Express, ste
trabaja con Microsoft .NET Framework 2.0 y por lo tanto, utiliza ADO.NET 2.0, el cul
aade algunas caractersticas nuevas adicionales.
En nuestro caso, nos centraremos nica y exclusivamente en ADO.NET como modelo
de objetos de acceso a datos para la plataforma .NET de Microsoft, ya que es el mismo
para cualquier tipo de versin de ADO.NET.


78u0 es A"$.NET9
ADO.NET posee las funcionalidades de ADO con las posibilidades aadidas del uso de
documentos XML de forma nativa, junto a una disposicin de objetos que aumentan el
rendimiento de los desarrolladores, y posibilitan ms an, el trabajo y desarrollo de
aplicaciones en n-capas.
Para el que no sepa que es ADO ni ADO.NET, el resumen de ADO.NET sera el de un
conjunto de clases que nos permite leer e interactuar con fuentes de datos
almacenadas en bases de datos y otras fuentes de almacenamiento de datos.
302
ADO.NET proporciona diferentes clases del nombre de espacio S%stem./ata dentro
de las cules, destacaremos por encima de todas, la clase /ataVie, la clase
/ataSet y la clase /ataTa#le.
Este conjunto de clases de carcter armnico, funcionan de igual forma con la capa
inferior que es la que corresponde a los proveedores de acceso a datos con los que
podemos trabajar.
Esto facilita el trabajo en n-capas y la posible migracin de aplicaciones que utilicen
una determinada fuente de datos y deseemos en un momento dado, hacer uso de otra
fuente de datos.


78u0 pasa con A"$ EecordSet9
*DO 'ecordSet pertenece a ADO y como hemos dicho al principio, es una parte de
ADO y por lo tanto lo debemos olvidar.
La forma de trabajar de ADO a ADO.NET vara, pero para que vea que ADO.NET no es
tan complicado y que complementa en muchas cosas lo que sabemos de ADO, diremos
que la funcionalidad de *DO 'ecordSet ha sido sustituida por los objetos /ataSet y
/ataBeader de ADO.NET.
Cuando veamos ms adelante cada una de las partes tericas en un ejemplo prctico,
observaremos que el trabajo con fuentes de datos es realmente sencillo.


78u0 capas o 6u0 partes #ay dentro de A"$.NET9
Dentro de ADO.NET tenemos dos partes importantes.
La primera de ellas es la que corresponde con el nombre de espacio S%stem./ata y
que constituye los objetos y clases globales de ADO.NET.
La otra parte es la que corresponde con los objetos que permiten el acceso a datos a
una determinada fuente de datos desde ADO.NET y que utilizan as mismo, las clases
del nombre de espacio S%stem./ata.
Esta ltima parte, queda constituida por las clases y objetos de los diferentes
proveedores de acceso a datos como se muestra en la figura 1.
&isin "eneral de las clases de AD:*;$
Figura 1
303
Para resumir de alguna forma lo que estamos comentando, diremos que el trabajo de
conexin con la base de datos, la ejecucin de una instruccin SQL determinada, una
vista, etc., la realiza el proveedor de acceso a datos.
Recuperar esos datos para tratarlos, manipularlos o volcarlos a un determinado control
o dispositivo, es accin de la capa superior que corresponde con el nombre de espacio
S%stem./ata.
A continuacin veremos todo esto con ms detalle y comprenderemos de una forma
ms clara cada una de las partes que componen el modelo de trabajo con ADO.NET.


78u0 nos permite realmente A"$.NET cuando trabaamos con G%'9
El entorno de Microsoft .NET Framework nos proporciona el trabajo con estndares y
con ello, la posibilidad de trabajar con diferentes tipos de aplicaciones, entornos,
sistemas operativos y lenguajes sin necesidad de conocer lo que hay al otro lado de
nuestra aplicacin.
XML es sin lugar a dudas, el lenguaje de etiquetas por excelencia, vlido para llevar a
cabo esta tarea sin tener un impacto relevante cuando trabajamos con diferentes
soluciones en entornos dispares.
Tanto la posibilidad de trabajar con Servicios Web XML como con documentos e
informacin en XML, sobre todo al trabajar con fuentes de datos en ADO.NET, nos
proporciona a los desarrolladores las posibilidades necesarias que nos permite hacer
que la informacin con la que trabajamos, pueda ser tratada entre diferentes sistemas
o entornos, sin que por ello nos preocupemos de lo que hay al otro lado.

304
%(dulo B ? Cap!tulo @
1. System."ata
Las clases del nombre de espacio S%stem./ata son bastantes extensas y variadas.
Quizs las clases ms importantes son la clase /ataVie, la clase /ataSet y la clase
/ataTa#le.


'a clase "ataSet
Puede que sea la capa ms externa e importante del modelo ADO.NET, pero es la que
contiene quizs, el modelo de colecciones y trabajo que ms le puede resultar familiar
al programador de Visual Basic 6, sobre todo a los anteriormente comentados
'ecordSets.
El DataSet contiene en s, un conjunto de datos que han sido volcados desde el
proveedor de datos.
De esa forma, podemos trabajar con ellos como lo hacamos en Visual Basic 6 por
ejemplo.
De hecho, por marcar una similitud con el 'ecordSet, el DataSet est preparado para
trabajar con fuentes de datos desconectadas.
La novedad quizs ms destacable, es que cuando trabajamos con DataSets, el origen
de datos no es lo ms importante, ya que ste, puede ser cualquier tipo de origen de
datos. No tiene porqu ser una base de datos.
Un DataSet contiene colecciones de DataTables y Data'elations.
El DataTable contiene una tabla o tablas, mientras que la Data'elation contiene las
relaciones entre las DataTables.
Sin embargo, no es necesario especificar todo esto hasta el ltimo detalle como
veremos ms adelante.


'a clase "ataVieF
Este objeto nos permite crear mltiples vistas de nuestros datos, adems de
permitirnos presentar los datos.
Es la clase que nos permite representar los datos de la clase DataTable,
permitindonos editar, ordenar y filtrar, buscar y navegar por un conjunto de datos
determinado.


'a clase "ataTable
Este objeto nos permite representar una determinada tabla en memoria, de modo que
podamos interactuar con ella.
A la hora de trabajar con este objeto, debemos tener en cuenta el nombre con el cul
definamos una determinada tabla, ya que los objetos declarados en en el DataTable es
sensitivo a maysculas y minsculas.


7#servacin3
)Ijese 9ue mientras 9ue en #isual Basic G utili.@bamos el 'ecordSet y
305
9ue :ste3 era la representaci<n en memoria de una ;nica tabla3 en
*DO.$%T3 podemos representar una base de datos o un conjunto de
tablas en memoria mediate un DataSet
:n pe6ue+o eemplo pr&ctico
El siguiente ejemplo prctico, nos ensea a utilizar un DataSet y nos muestra como
podemos acceder a los objetos que dependen de un DataSet para recuperar por
ejemplo, los campos y propiedades de una determinada tabla o tablas.
Im2orts S-stem/Data
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
Dim ConeGion As String =
"ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo"
Dim Hi1abla As Data1able
Dim HiCol!mna As DataCol!mn
Dim HiDataSet As AeJ DataSet()
Dim Coman%o As AeJ SIlDataA%a2ter("S'C1 O )"0H A']FI'"S",
ConeGion)
Coman%o/)ill(HiDataSet, "A']FI'"S")
4 "ecorremos las tablas
)or ach Hi1abla In HiDataSet/1ables
1eGt,oG1/1eGt B= "1ablaD " P Hi1abla/1ableAame P 5bCr'8 P 5bCr'8
4 "ecorremos las Col!mnas %e ca%a 1abla
)or ach HiCol!mna In Hi1abla/Col!mns
1eGt,oG1/1eGt B= HiCol!mna/Col!mnAame P 5b1ab P +
"(" P HiCol!mna/Data1-2e/Aame P ")" P 5bCr'8
AeGt
AeGt
306
Coman%o = Aothing
n% S!b
n% Class
Nuestro ejemplo en ejecucin es el que se muestra en la figura 1.
jemplo en ejecucin del uso de Data!et8 Data$able y DataColumn
Figura 1


307
%(dulo B ? Cap!tulo @
A. 'os proveedores de acceso a datos
Los proveedores de acceso a datos es la capa inferior de la parte correspondiente al
acceso de datos y es la responsable de establecer la comunicacin con las fuentes de
datos.
En este conjunto de nombres de espacio, encontraremos casi siempre las clases
-onnection, -ommand, /ata4dapter y /ataBeader como las clases ms
generales, las cuales nos permiten establecer la conexin con la fuente de datos.


,roveedores de acceso a datos de .NET <rameForI
Dentro del entorno .NET Framework, encontramos un nutrido conjunto de proveedores
de acceso a datos.
Estos son los siguientes:
ODBC .$%T Data +roider
OL% DB .$%T Data +roider
Oracle Client .$%T Data +roider
SEL Serer .$%T Data +roider
Estos proveedores de acceso a datos incluidos en Microsoft .NET Framework, los
podemos encontrar en los nombres de espacio:
System.Data.Odbc
System.Data.OleDb
System.Data.OracleClient
System.Data.S9lClient
El proveedor ODBC .NET permite conectar nuestras aplicaciones a fuentes de datos a
travs de ODBC.
El programador de Visual Basic 6 est ampliamente familiarizado con este mtodo de
acceso a datos, y nos permite acceder a un amplio conjunto de fuentes de datos.
El proveedor OLE DB .NET permite conectar nuestras aplicaciones a fuentes de datos a
travs de OLE DB.
Al igual que en el caso anterior, el programador de Visual Basic 6 est ampliamente
familiarizado con este mtodo de acceso a datos.
El proveedor Oracle Client .NET es un proveedor de acceso a datos especialmente
diseado para bases de datos Oracle.
Por ltimo, el proveedor SQL Server .NET es un proveedor de acceso a datos nativo,
que nos permite conectar nuestras aplicaciones a fuentes de datos Microsoft SQL
Server 7 o posterior.
Se trata de un proveedor especfico para bases de datos Microsoft SQL Server 7.0,
Microsoft SQL Server 2000 y Microsoft SQL Server 2005.
-onse(o3
Siempre 9ue pueda3 utilice para acceder a fuentes de datos3 un
proeedor de acceso a datos natio. %sto le permitir@ aumentar
considerablemente el rendimiento a la "ora de establecer la cone&i<n
con una determinada fuente de datos
308
Los proveedores de acceso a datos que distribuye Microsoft en ADO.NET y algunos
desarrollados por otras empresas o terceros, contienen los mismos objetos, aunque los
nombres de stos, sus propiedades y mtodos, pueden ser diferentes.
Ms adelante veremos algn ejemplo, y observar en la prctica cules son estas
diferencias ms destacables.


$tros proveedores de acceso a datos
Si bien el proveedor de acceso a datos es el mecanismo a travs del cul podemos
establecer una comunicacin nativa con una determinada fuente de datos, y dado que
Microsoft proporciona los proveedores de acceso a datos ms corrientes, es cierto que
no los proporciona todos, si bien, con OLE DB y ODBC, podemos acceder a la inmensa
totalidad de ellos.
Sin embargo, hay muchos motores de bases de datos de igual importancia como
Oracle, MySql, AS/400, etc.
En estos casos, si queremos utilizar un proveedor de acceso a datos nativo,
deberemos acudir al fabricante o a empresas o iniciativas particulares para que nos
proporcionen el conjunto de clases necesarias que nos permitan abordar esta accin.


El obeto Connection
Este objeto es el encargado de establecer una conexin fsica con una base de datos
determinada.
Para establecer la conexin con una determinada fuente de datos, no slo debemos
establecer la cadena de conexin correctamente, sino que adems deberemos usar los
parmetros de conexin y el proveedor de acceso a datos adecuado.
Con este objeto, podremos adems abrir y cerrar una conexin.


El obeto Command
Este objeto es el que representa una determinada sentencia SQL o un Stored
Procedure.
Aunque no es obligatorio su uso, en caso de necesitarlo, lo utilizaremos conjuntamente
con el objeto Data*dapter que es el encargado de ejecutar la instruccin indicada.


El obeto "ataAdapter
Este objeto es quizs el objeto ms complejo y a la vez complicado de todos los que
forman parte de un proveedor de acceso a datos en .NET.
Cuando deseamos establecer una comunicacin entre una fuente de datos y un
DataSet, utilizamos como intermediario a un objeto Data*dapter.
A su vez, un Data*dapter contiene 4 objetos que debemos conocer:
SelectCommand es el objeto encargado de realizar los trabajos de seleccin
de datos con una fuente de datos dada.
En s, es el que se encarga de devolver y rellenar los datos de una fuente de
datos a un DataSet.
DeleteCommand es el objeto encardago de realizar las acciones de borrado de
datos.
InsertCommand es el objeto encardago de realizar las acciones de insercin
de datos.
309
,pdateCommand es el objeto encardago de realizar las acciones de
actualizacin de datos.
Los objetos DeleteCommand, InsertCommand y ,pdateCommand son los objetos que
se utilizan para manipular y transmitir datos de una fuente de datos determinada, al
contrario del objeto SelectCommand que tan slo interacta con la fuente de datos
para recuperar una porcin o todos los datos indicados en el objeto Command
anteriormente comentado.


El obeto "ataEeader
Este objeto es el utilizado en una sla direccin de datos.
Se trata de un objeto de acceso a datos muy rpido.
Este objeto puede usar a su vez el objeto Command o el mtodo %&ecute'eader.


%(dulo B ? Cap!tulo @
B. El concepto "ata.inding
Una palabra nueva para los desarrolladores y programadores de Visual Basic 6, es el
concepto denominado DataBinding o DataBind.
A continuacin, explicaremos en qu consiste este concepto.


El uso de "ata.ind
El mtodo DataBind se utiliza para rellenar de datos un determinado control o clase.
Muchos controles y clases, posee este mtodo al que le asignaremos un conjunto de
datos para que se rellene con ellos, pudiendo despus interactuar con los datos de
forma directa.
310
En s, un DataBinding es un enlace a datos que se encarga de rellenar de datos a un
determinado control o clase.
Como ejemplo de esto, veremos como rellenar un control Te;tBo; con un dato
utilizando este mtodo.
Iniciaremos una nueva aplicacin Windows y escribiremos el siguiente cdigo fuente:
Im2orts S-stem/Data
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
Dim ConeGion As String =
"ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo"
Dim HiDataSet As AeJ DataSet()
Dim Coman%o As AeJ SIlDataA%a2ter("S'C1 1I1F'0 )"0H A']FI'"S,
?'ICF'AS <H" ?'ICF'AC0D,A""AS = C0D,A""AS AAD S0CI0AI) = 41111114",
ConeGion)
4 "ellenamos el DataSet con el conteni%o
4 %e la sentencia S'C1
Coman%o/)ill(HiDataSet, "?'IS")
4 "ellenamos el control 1eGt,oG1 con el
4 %ato corres2on%iente a la 2rimera 8ila
4 %e la sentencia S'C1 e#ec!ta%a
1eGt,oG1/Data,in%ings/A%%("1eGt", HiDataSet, "?'IS/1I1F'0")
Coman%o = Aothing
n% S!b
n% Class
Nuestro ejemplo en ejecucin es el que se muestra en la figura 1.
311
jemplo en ejecucin del uso de Data#indin"
Figura 1

%(dulo B ? Cap!tulo @
3. $tras consideraciones
Dentro de las conexiones a fuentes de datos, hay algunas partes de stas que
permanecen a veces en el olvido y su importancia sin embargo, es bastante grande.
312
La accin ms pesada cuando realizamos un acceso a una fuente de datos, se
encuentra en la conexin con la fuente de datos.
Esa tarea, simple tarea, es la que ms recursos del sistema consume cuando
accedemos a fuentes de datos.
Esto lo debemos tener en cuenta, y por lo tanto, variante de esto que comentamos
son las siguientes premisas:
La conexin debe realizarse siempre que se pueda, con los proveedores de
acceso a datos nativos, que por lo general salvo raras expceciones, sern ms
rpidos que los accesos a fuentes de datos a travs de proveedores del tipo OLE
DB y ODBC.
La conexin con la fuente de datos (apertura de la conexin), debe realizarse
lo ms tarde posible. Es recomendable definir todas las variables que podamos,
antes de realizar la conexin.
La conexin debe cerrarse lo antes posible, siempre y cuando no tengamos la
necesidad de utilizar la conexin previamente abierta.
Hay ms particularidades a tener en cuenta cuando trabajamos con fuentes de datos.
El hecho de que con un DataSet podamos trabajar con datos desconectados, no
significa que dentro de l, podamos abrir una tabla con una cantidad de registros
enormes, y trabajemos sobre ella creyendo que esto nos beneficiar.
Todo lo contrario.
Aunque los desarrolladores de Visual Basic 6 ya saben que esta prctica penaliza
seriamente el rendimiento de nuestras aplicaciones, conviene sealarlo nuevamente
para que no haya ningn tipo de duda al respecto.

-ntroducci(n
Ahora que ya tenemos un poco ms clara la estructura del modelo de acceso a datos
ADO.NET, podemos adentrarnos en todo lo que rodea al acceso conectado de base de
datos y la manipulacin y trabajo de datos conectados.
A continuacin, encontrar el ndice detallado de este captulo.
313
%(dulo B ? Cap!tulo 1

1. El paradigma de la conexin
2. Conociendo el objeto DataReader
3. Un primer contacto con el objeto DataReader
4. Trabaja DataReader en un ambiente conectado realmente?
5. Usando DataSource con DataReader
6. Usando los componentes de acceso a datos de .NET



%(dulo B ? Cap!tulo 1
@. El paradigma de la cone;i(n
Cuando abordamos un proyecto de acceso a fuentes de datos, siempre nos
encontramos con una duda existencial.
Debemos crear una conexin con la base de datos al principio de nuestra aplicacin y
cerrarla cuando la aplicacin se cierre?, o debemos crear una conexin con la base de
datos slo cuando vayamos a trabajar con la fuente de datos?. Y si estamos
trabajando continuamente con una fuente de datos?, cmo penalizaran todas estas
acciones?.
Es difcil de asumir que accin tomar en cada caso, y es que dependiendo de lo que
vayamos a realizar, a veces es ms efectiva una accin que otra, y en otras ocasiones,
no est del todo claro, ya que no existe en s una regla clara que especifique qu
accin tomar en un momento dado.
314
Lo que s est claro es que el modelo de datos de ADO.NET que hemos visto, quedara
resumido en cuanto a la conectividad de la manera en la que se representa en la
figura 1.
&isin "eneral de AD:*;$ respecto a la conectividad con bases de datos
Figura 1
El objeto DataSet nos ofrece la posibilidad de almacenar datos, tablas y bases de
datos de una determinada fuente de datos.
De esta manera, podemos trabajar con las aplicaciones estando desconectados de la
fuente de datos.
Sin embargo, a veces necesitamos trabajar con la fuente de datos estando conectados
a ella.
El objeto Data'eader nos ofrece precisamente la posibilidad de trabajar con fuentes de
datos conectadas.
Por otro lado, el objeto Data'eader tiene algunas particularidades que conviene
conocer y que veremos a continuacin.
315

%(dulo B ? Cap!tulo 1
1. Conociendo el obeto "ataEeader
El objeto Data'eader nos permite como hemos indicado anteriormente, establecer una
conexin con una fuente de datos y trabajar con esta fuente de datos sin
desconectarnos de ella, sin embargo, hay diferentes cualidades y particularidades que
conviene conocer.


"ataEeader es de s(lo lectura
Lo que hemos dicho anteriormente, requiere sin embargo, que esta conexin se
establezca en un modo de s<lo lectura, al contrario de lo que se puede hacer con el
objeto DataSet, con el que podemos interactuar con la fuente de datos en modo
lectura y modo escritura.


"ataEeader se manea en una s(la direcci(n
El objeto Data'eader slo permite que nos desplacemos por los datos en una sla
direccin, sin vuelta atrs.
Por el contrario, el objeto DataSet nos permite movernos por los registros para
adelante y para atrs.
Adems, slo podemos utilizar el objeto Data'eader con conexiones establecidas en
una sentencia SQL por ejemplo, pero no podemos variar esta.
Para hacerlo, debemos entonces modificar la conexin con el comando establecido.


"ataEeader es r&pido
316
Debido a su naturaleza y caractersticas, este objeto es bastante rpido a la hora de
trabajar con datos.
Como es lgico, consume adems menos memoria y recursos que un objeto DataSet
por ejemplo.
Sin embargo, dependiendo de las necesidades con las que nos encontremos, puede
que este mtodo de acceso y trabajo no sea el ms idneo.
El desarrollador Visual Basic 6, encontrar en este objeto, una gran similitud con el
conocido y comentado 'ecordSet.


Anali*ando el fluo de trabao de "ataEeader
Cuando trabajamos con fuentes de datos conectadas, trabajaremos con el objeto
Data'eader.
Para trabajar con este objeto, utilizaremos los objetos siguientes del proveedor de
acceso a datos:
Connection
Command
Data'eader
Un resumen grfico de esto es lo que podemos ver en la figura 1.
l flujo de conectividad de Data3eader
Figura 1
317

%(dulo B ? Cap!tulo 1
A. :n primer contacto con el obeto "ataEeader
A continuacin veremos un ejemplo simple, sencillo y que si usted est acostumbrado
a utilizar Visual Basic 6 y ADO, le resultar especialmente familiar.


:n eemplo simple para entenderlo meor
Tenga en cuenta que en el siguiente ejemplo nos conectaremos a Microsoft SQL Server
y recorreremos los registros uno a uno en un ambiente conectado y volcaremos estos
registros en un control Te;tBo;.
Im2orts S-stem/Data
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
Dim ConeGion As String =
"ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo"
318
Dim HiConeGion As AeJ SIlConnection(ConeGion)
Dim HiData"ea%er As SIlData"ea%er
Dim Coman%o As AeJ SIlComman%("S'C1 1I1F'0 )"0H A']FI'"S,
?'ICF'AS <H" ?'ICF'AC0D,A""AS = C0D,A""AS AAD S0CI0AI) = 41111114",
HiConeGion)
HiConeGion/02en()
HiData"ea%er = Coman%o/Gec!te"ea%er()
<hile HiData"ea%er/"ea%()
1eGt,oG1/1eGt B= HiData"ea%er("1I1F'0") P 5bCr'8
n% <hile
Coman%o = Aothing
HiConeGion/Close()
n% S!b
n% Class
El cdigo de ejemplo en ejecucin es el que se muestra en la figura 1.
jemplo en ejecucin del uso simple de Data3eader
Figura 1
Este es un ejemplo simple del uso de Data'eader.
Sin embargo, el objeto Data'eader contiene un conjunto de propiedades y mtodos
que nos proporcionan acciones determinadas.
Por ejemplo, en el ejemplo anterior, hemos dado por hecho que la ejecucin de la
instruccin Select nos devolver uno o ms valores, pero podramos tambin saber
antes de manipular y trabajar con los posibles datos, si hay o no informacin.
Esto lo conseguimos con el mtodo 7as'o!s.
319

%(dulo B ? Cap!tulo 1
B. 7Trabaa "ataEeader en un ambiente conectado
realmente9
Pese a todo esto, que ocurre si trabajando en un ambiente conectado se desconecta
el servidor de acceso a datos?.
Imaginemos por un instante, que la conexin con SQL Server se establece
correctamente y que en un momento dado se detiene el servicio del servidor de base
de datos.
Esto es lo que veremos en el siguiente ejemplo.


"esenc#unfando la fuente de datos usando "ataEeader
Inicie un nuevo proyecto, inserte en el formulario de la aplicacin un control Te;tBo;
y un control Button, y escriba el cdigo que se detalla a continuacin:
Im2orts S-stem/Data
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
320
?ri5ate ConeGion As String =
"ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo"
?ri5ate strS]' As String = "S'C1 1I1F'0 )"0H A']FI'"S, ?'ICF'AS
<H" ?'ICF'AC0D,A""AS = C0D,A""AS AAD S0CI0AI) = 41111114"
?ri5ate HiConeGion As AeJ SIlConnection(ConeGion)
?ri5ate HiData"ea%er As SIlData"ea%er
?ri5ate Conta%or As 'ong = 0
?ri5ate ?osicion As 'ong = 0
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 stablecemos la ConeGiSn con la base %e %atos
stablecer+ConeGion(1r!e)
4 Si ha- %atos los mostramos, sino %eshabilitamos
4 la o2ciSn (botSn) 2ara recorrerlos
I8 Aot HiData"ea%er/Has"oJs 1hen
,!tton1/nable% = )alse
lse
,!tton1+ClicQ(sen%er, e)
n% I8
n% S!b
?ri5ate S!b stablecer+ConeGion(,-$al bolAccion As ,oolean)
Dim Coman%o As SIlComman%
I8 bolAccion 1hen
4 1r!e =* stablecemos la coneGiSn
Coman%o = AeJ SIlComman%(strS]', HiConeGion)
4 Abrimos la ConeGiSn
HiConeGion/02en()
4 #ec!tamos la sentencia S]'
HiData"ea%er = Coman%o/Gec!te"ea%er()
4 0btenemos la canti%a% %e registros obteni%os
321
Conta%or = HiData"ea%er/$isible)iel%Co!nt() B 1
lse
4 )alse =* )inali&amos la coneGiSn
,!tton1/nable% = )alse
4 Cerramos la ConeGiSn
Coman%o = Aothing
HiConeGion/Close()
n% I8
n% S!b
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
4 "ecorremos los registros - los mostramos
?osicion B= 1
HiData"ea%er/"ea%()
1eGt,oG1/1eGt = HiData"ea%er("1I1F'0")
4 Si hemos recorri%o el ob#eto 2or com2leto,
4 8inali&amos la ConeGiSn - %eshabilitamos el control
4 ,!tton I!e nos 2ermite rec!2erar los registros
I8 ?osicion = Conta%or 1hen
stablecer+ConeGion()alse)
n% I8
n% S!b
n% Class
Suponiendo que tenemos en nuestra base de datos varios registros, ejecute la
aplicacin.
Si todo ha ido como se esperaba, observaremos que nuestra aplicacin tiene un
aspecto como el que se muestra en la figura 1.
322
jemplo en ejecucin del uso de Data3eader en un ambiente conectado8 for4ando la descone5in de la fuente de datos
Figura 1
En este punto, detenga el sevicio de SQL Server y pulse el botn Siguiente ??.
Observar que la aplicacin sigue funcionando.
En este punto se har la pregunta que todos nos hemos hecho, no es el objeto
DataReader un objeto conectado?, cmo es posible que funcione si hemos detenido el
servicio de SQL Server?.
La respuesta es sencilla.
El objeto Data'eader recupera un nutrido conjunto de valores llenando un pequeo
buffer de datos e informacin.
Si el nmero de registros que hay en el buffer se acaban, el objeto Data'eader
regresar a la fuente de datos para recuperar ms registros.
Si el servicio de SQL Server est detenido en ese momento o en su caso, la fuente de
datos est parada, la aplicacin generar un error a la hora de leer el siguiente
registro.
En s, Data'eader es un objeto conectado, pero trabaja en bac6ground con un
conjunto de datos, por lo que a veces nos puede resultar chocante su comportamiento
como el ejemplo que comento.
Pese a las dudas planetadas, si tiene profundos conocimientos sobre el objeto
'ecordSet, encontrar familiar estas caractersticas.
323

%(dulo B ? Cap!tulo 1
3. :sando "ataSource con "ataEeader
Podemos usar el mtodo DataSource con el objeto Data'eader?.


"emostraci(n del uso de "ataSource con "ataEeader
La respuesta es s, pero en ADO.NET 2.0, se ha incorporado un nuevo mtodo al
objeto DataTable que le permite tener mayor independencia respecto al modo en el
que nos conectemos y recuperemos datos de una fuente de datos.
Recuerde que podemos recuperar datos en modo conectado Data'eader o en modo
desconectado DataSet.
Este mtodo que se ha incorporado a ADO.NET y que tiene por nombre *oad, nos
permite cargar un Data'eader para volcarlo a continuacin dentro de un control como
por ejemplo el control Data1rid#ie!.
Lo mejor es que veamos como funciona esto con un ejemplo que nos ayude a
comprender mejor la teora.
Inserte en un formulario un control Data1rid#ie! y escriba el siguiente cdigo:
Im2orts S-stem/Data
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
324
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos las 5ariables a !tili&ar
Dim ConeGion As String =
"ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo"
Dim strS]' As String = "S'C1 1I1F'0 )"0H A']FI'"S, ?'ICF'AS
<H" ?'ICF'AC0D,A""AS = C0D,A""AS AAD S0CI0AI) = 41111114"
Dim HiConeGion As AeJ SIlConnection(ConeGion)
Dim HiData"ea%er As SIlData"ea%er
Dim HiData1able As AeJ Data1able
Dim Coman%o As SIlComman%
4 stablecemos la ConeGiSn con la base %e %atos
Coman%o = AeJ SIlComman%(strS]', HiConeGion)
4 Abrimos la ConeGiSn
HiConeGion/02en()
4 #ec!tamos la sentencia S]'
HiData"ea%er = Coman%o/Gec!te"ea%er()
4 Cargamos los res!lta%os en el ob#eto Data1able
HiData1able/'oa%(HiData"ea%er, 'oa%02tion/05erJriteChanges)
4 $olcamos los %atos en el control Data;ri%$ieJ
Data;ri%$ieJ1/DataSo!rce = HiData1able
4 Cerramos la ConeGiSn
Coman%o = Aothing
HiConeGion/Close()
n% S!b
n% Class
Nuestro ejemplo en ejecucin es el que podemos ver en la figura 1.
325
jemplo en ejecucin del uso de Data3eader y Data!ource en un control Data<rid&ie7
Figura 1
Con todo y con esto, lo que realmente es curioso, es que hemos olvidado por un
instante que el objeto Data'eader es un objeto de slo lectura que funciona en una
nica direccin, hacia delante.
Qu significa esto o como puede influir o como podemos aprovechar esta
circunstancia en nuestros desarrollos?.


Carga segmentada de datos con "ataSource y "ataEeader
Si recuperamos los datos de una fuente de datos con Data'eader y leemos algunos de
sus datos y posteriormente, ejecutamos el mtodo DataSource, el resto de datos,
aquellos datos que quedan en el Data'eader, sern los que se vuelquen en el control
que definamos como destino de los datos.
Imaginemos el ejemplo anterior, y el siguiente cdigo fuente.
Im2orts S-stem/Data
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos las 5ariables a !tili&ar
326
Dim ConeGion As String =
"ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo"
Dim strS]' As String = "S'C1 1I1F'0 )"0H A']FI'"S, ?'ICF'AS
<H" ?'ICF'AC0D,A""AS = C0D,A""AS AAD S0CI0AI) = 41111114"
Dim HiConeGion As AeJ SIlConnection(ConeGion)
Dim HiData"ea%er As SIlData"ea%er
Dim HiData1able As AeJ Data1able
Dim Coman%o As SIlComman%
4 stablecemos la ConeGiSn con la base %e %atos
Coman%o = AeJ SIlComman%(strS]', HiConeGion)
4 Abrimos la ConeGiSn
HiConeGion/02en()
4 #ec!tamos la sentencia S]'
HiData"ea%er = Coman%o/Gec!te"ea%er()
4 'eemos el 2rimer registro - asK nos 2osicionamos
4 a 2artir %el seg!n%o %e ellos
HiData"ea%er/"ea%()
4 Cargamos los res!lta%os en el ob#eto Data1able
HiData1able/'oa%(HiData"ea%er, 'oa%02tion/05erJriteChanges)
4 $olcamos los %atos en el control Data;ri%$ieJ
Data;ri%$ieJ1/DataSo!rce = HiData1able
4 Cerramos la ConeGiSn
Coman%o = Aothing
HiConeGion/Close()
n% S!b
n% Class
En este caso, lo que ocurre como ya hemos comentado, es que los datos que se
cargan son los que an no han sido leidos en el objeto Data'eader, por lo que se
mostrarn todos los datos desde el ltimo ledo hasta llegar al final del objeto.

327

%(dulo B ? Cap!tulo 1
C. :sando los componentes de acceso a datos de .NET
Los componentes del entorno .NET nos proporcionan las caractersticas necesarias
para poder acceder a fuentes de datos de forma rpida y sencilla.
Imaginemos por lo tanto, una situacin lo ms parecida o similar posible a la que
podramos tener con un programa Visual Basic 6 y un 'ecordSet.
El mejor ejemplo de esto que comento es el que veremos a continuacin.
"emostraci(n del uso de .indingSource y .indingNavigator
Para ello, crearemos un proyecto nuevo e insertaremos un control BindingSource y un
control Binding$aigator dentro del formulario.
Tambin insertaremos un control Te&tBo& al formulario, dnde presentaremos la
informacin sobre la que navegaremos.
Nuestro formulario con los controles insertados en l, tendr un aspecto similar al que
se presenta en la figura 1.
328
Controles de nave"acin y acceso a datos dispuestos en el formulario
Figura 1
Una vez llegado a este punto, lo que tendremos que hacer a continuacin ser escribir
el cdigo fuente necesario para poder representar los datos de la sentencia SQL en el
control Bingind$aigator, para que a su vez los presente en el control Te&tBo&.
A continuacin se indica el cdigo fuente de esta parte de demostracin de la
aplicacin.
Im2orts S-stem/Data
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Declaramos las 5ariables a !tili&ar
329
Dim ConeGion As String =
"ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo"
Dim strS]' As String = "S'C1 1I1F'0 )"0H A']FI'"S, ?'ICF'AS
<H" ?'ICF'AC0D,A""AS = C0D,A""AS AAD S0CI0AI) = 41111114"
Dim HiConeGion As AeJ SIlConnection(ConeGion)
Dim HiData"ea%er As SIlData"ea%er
Dim HiData1able As AeJ Data1able
Dim Coman%o As SIlComman%
4 stablecemos la ConeGiSn con la base %e %atos
Coman%o = AeJ SIlComman%(strS]', HiConeGion)
4 Abrimos la ConeGiSn
HiConeGion/02en()
4 #ec!tamos la sentencia S]'
HiData"ea%er = Coman%o/Gec!te"ea%er()
4 Cargamos los res!lta%os en el ob#eto Data1able
HiData1able/'oa%(HiData"ea%er, 'oa%02tion/05erJriteChanges)
4 $olcamos los %atos en el control 1eGt,oG
,in%ingSo!rce1/DataSo!rce = HiData1able
,in%ingAa5igator1/,in%ingSo!rce = ,in%ingSo!rce1
1eGt,oG1/Data,in%ings/A%%(AeJ ,in%ing("1eGt", ,in%ingSo!rce1,
"1I1F'0", 1r!e))
4 Cerramos la ConeGiSn
Coman%o = Aothing
HiConeGion/Close()
n% S!b
n% Class

330

-ntroducci(n
Ya tenemos claro el funcionamiento con fuentes de datos conectadas, sin embargo,
trabajar con datos conectados slo es necesario en algunos mbitos, lo ms habitual,
ser que nos encontremos trabajando con ambientes y accesos a datos
desconectados, como ocurrir en la inmensa mayora de la veces.
A continuacin, aprender a utilizar el DataSet y DataAdapter para sacar el mximo
provecho a un ambiente desconectado de datos.
El ndice detallado de este captulo es el que se indica a continuacin.
%(dulo B ? Cap!tulo A

1. Esquema general de la estructura desconectada de acceso a datos
2. Conociendo el objeto DataAdapter
3. Insertando datos a travs del objeto DataAdapter
4. Actualizando datos a travs del objeto DataAdapter
5. Eliminando datos a travs del objeto DataAdapter


331

%(dulo B ? Cap!tulo A
@. Es6uema general de la estructura desconectada de
acceso a datos
En los captulos anteriores de este mdulo, hemos visto ya el uso de la clase DataSet.
Incluso lo hemos visto con algn ejemplo.
La clase DataSet est pensada y diseada para trabajar con fuentes de datos
desconectadas. Indudablemente, en este punto, debemos tener clara la estructura
general de cmo funciona el acceso desconectado con fuentes de datos.
En la figura 1, podemos observar el diagrama general de esta parte
structura "eneral del uso de Data!et en el acceso desconectado a datos
Figura 1
332


Connection/ "ataAdapter y "ataSet
Como podemos observar en la figura 1, para comunicarnos con una fuente de datos,
siempre deberemos establecer una conexin, independientemente de si la conexin
con la fuente de datos va a permanecer a lo largo del tiempo o no.
El objeto Connection nos permite por lo tanto, establecer la conexin con la fuente de
datos.
El objeto DataSet nos permite por otro lado, recoger los datos de la fuente de datos y
mandrselos a la aplicacin.
Entre medias de estos dos objetos, encontramos el objeto Data*dapter que hace las
funciones de puente o nexo de unin entre la conexin y el objeto DataSet.
Esto es lo que veremos a continuacin, como funciona el objeto Data*dapter, y como
encaja todo esto en el acceso a fuentes de datos desconectadas.


%(dulo B ? Cap!tulo A
1. Conociendo el obeto "ataAdapter
El objeto Data*dapter forma parte del proveedor de acceso a datos, tal y como se
muestra en la figura 1.
333
&isin "eneral de las clases de AD:*;$
Figura 1
Cada proveedor de acceso a datos posee su propio objeto Data*dapter.
Cuando realizamos alguna modificacin o accin sobre la fuente de datos, utilizaremos
siempre el objeto Data*dapter a caballo entre el objeto DataSet y la fuente de datos
establecida a travs de la conexin con el objeto Connection.
Con el objeto Data*dapter, podremos adems realizar diferentes acciones sobre
nuestras bases de datos, acciones como la ejecucin general de sentencias de SQL no
slo para seleccionar un conjunto de datos, sino para alterar el contenido de una base
de datos o de sus tablas.


Connection/ "ataAdapter y "ataSet
Antes de entrar en materia ms profundamente, diremos que en lo que respecta a los
proveedores de acceso a datos que vienen integrados con .NET, encontramos dos
formas de usar un Data*dapter.
La primera de ellas es utilizando los componentes del proveedor de acceso a datos.
La segunda de ellas es utilizando las clases del nombre de espacio del proveedor de
acceso a datos.
La mejor forma de entender todo esto que comentamos, es trabajando con un ejemplo
prctico que nos ensee a usar el objeto Data*dapter en Visual Basic 2005 Express.


:tili*ando las clases de .NET
En este primer ejemplo de demostracin del uso de Data*dapter a travs de cdigo
usando para ello las clases de .NET, estableceremos una conexin con SQL Server y
mostraremos los datos recogidos en un control Te&tBo&.
Iniciaremos Visual Basic 2005 Express y seleccionaremos un proyecto de formulario de
Windows. Dentro del formulario, insertaremos un control Te&tBo& y aadiremos dos
referencias al proyecto.
Las referencias aadidas sern a las libreras System.Data y System.J(L, como se
muestra en la figura 2.
334
3eferencias a las clases de acceso a datos de *;$
Figura 2
Una vez que hemos aadido las referencias necesarias para utilizar las clases que
queremos en nuestro proyecto, iremos al cdigo y escribiremos las siguientes
instrucciones:
Im2orts S-stem/Data
Im2orts S-stem/Data/SIlClient
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 stablecemos la ca%ena %e coneGiSn con la ,,DD
Dim ConeGion As String =
"ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo"
4 Declaramos el DataSet %Sn%e 5olcaremos los %atos
Dim HiDataSet As AeJ DataSet()
4 Declaramos el DataA%a2ter establecien%o
4 la coneGiSn con la 8!ente %e %atos
335
Dim Coman%o As AeJ SIlDataA%a2ter("S'C1 SocioAI), )echaAlI!iler
)"0H A']FI'"S", ConeGion)
4 "ellenamos el DataSet con el conteni%o %e la instr!cciSn S]'
Coman%o/)ill(HiDataSet)
4 Cerramos la coneGiSn con la ,,DD
Coman%o = Aothing
4 Declaramos la 2ro2ie%a% "oJ 2ara recorrer
4 las 8ilas conteni%as en el DataSet
Dim "oJ
4 "ecorremos to%as las 8ilas - las tratamos
)or ach "oJ In HiDataSet/1ables(0)/"oJs
1eGt,oG1/1eGt B= "oJ("SocioAI)")/1oString P 5b1ab P
"oJ(")echaAlI!iler") P 5bCr'8
AeGt
4 $aciamos el DataSet 2ara liberar memoria
HiDataSet = Aothing
n% S!b
n% Class
El ejemplo en ejecucin del uso de Data*dapter junto con las clases de .NET es el que
se muestra en la figura 3.
jemplo del acceso a datos con DataAdapter a travs de las clases de *;$
Figura 3
336


:tili*ando los componentes de .NET
Sin embargo y como ya hemos comentado, existe otro mtodo de acceso a fuentes de
datos diferente a las clases de .NET, el acceso a travs de componentes que nos
faciliten esa tarea.
Sin embargo, los componentes de acceso a datos, utilizan por detrs las clases de
.NET que hemos visto, lo que ocurre, es que simplifica enormemente el trabajo y
ahorra tiempo a la hora de desarrollar aplicaciones.
De todos los modos, todo depende de la utilidad o necesidades con las que nos
encontremos en un momento dado.
Iniciaremos un proyecto Windows nuevamente, e insertaremos en l un control
Te&tBo& como hicimos en el caso anterior.
A continuacin, aadiremos los componentes de acceso a fuentes de datos SQL Server
que es la fuente de datos origen.
Como hemos visto, para conectar a fuentes de datos SQL Server, hemos utilizado el
nombre de espacio System.Data y hemos importado en el proyecto los nombres de
espacio System.Data y System.Data.S9lClient.
Los componentes .NET de acceso a fuentes de datos de SQL Server, se identifican por
el nombre S9l&&&, siendo xxx el tipo de componente a utilizar.
Para poder utilizarlos, deberemos aadirlo a la barra de herramientas.
Para aadir los componentes a nuestro proyecto, haremos soble clic sobre el
formulario y posteriormente haremos clic con el botn derecho del ratn sobre la barra
de herramientas y seleccionaremos la opcin %legir elementos... como se muestra en
la figura 4.
:pcin de la barra de %erramientas para a2adir componentes al entorno
Figura 4
337
Una vez que hemos hecho esto, seleccionaremos los componentes S9lCommand,
S9lCommandBuilder, S9lConnection, S9lData*dapter y S9lDataSource, tal y como se
muestra en la figura 5.
Componentes a a2adir al entorno
Figura 5
Una vez que hemos aadido los componentes al entorno, estos quedarn dispuestos
dentro de la barra de herramientas como se indica en la figura 6.
338
Componentes a2adidos en la barra de %erramientas
Figura 6
Lo primero que haremos ser insertar un componente S9lConnection dentro del
formulario.
Acudiremos a la ventana de propiedades del componente y modificaremos la
propiedad "onnection.trin' dentro de la cul escribiremos la instruccin:
sererS.TuidSsaTpass!ordS#isualBasicTdatabaseS(SD$#ideo
entendiendo que sta, es la cadena de conexin vlida con nuestra base de datos.
A continuacin aadiremos el componente S9lData*dapter a nuestro formulario.
Si se abre alguna ventana, cirrela.
Vamos a configurar el control con la ventana +ropiedades. Podramos haberlo hecho
desde el asistente que se nos ha abierto, pero lo vamos a hacer de otra forma menos
sencilla.
Sitese sobre la propiedad SelectCommand, y dentro de sta, en la propiedad
Connection.
Lo que vamos a hacer, es asignar al componente S9lData*dapter el componente de
conexin que vamos a usar para establecer la comunicacin entre la fuente de datos y
nuestra aplicacin.
Despliegue la propiedad Connection indicada, y seleccione el componente de conexin
S9lConnectionH anteriormente configurado, tal y como se muestra en la figura 7.
339
Componente !qlDataAdapter con la cone5in establecida para ser usada en la ejecucin de nuestra aplicacin
Figura 7
Por ltimo, inserte un componente DataSet al formulario.
Todos los componentes quedarn por lo tanto insertados, tal y como se indica en la
figura 8.
340
Componentes a2adidos en el formulario de nuestra aplicacin
Figura 8
Una vez que tenemos todo preparado, tan slo nos queda escribir la parte de cdigo
fuente necesario para poder realizar todas las operaciones y acciones que
necesitamos.
A continuacin, se expone el cdigo fuente de nuestra aplicacin de demostracin:
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 stablecemos la ca%ena S]' a !tili&ar
SIlDataA%a2ter1/SelectComman%/Comman%1eGt = "S'C1 SocioAI),
)echaAlI!iler )"0H A']FI'"S"
4 Abrimos la ConeGiSn
SIlConnection1/02en()
4 "ellenamos el DataSet con el conteni%o %e la instr!cciSn S]'
341
SIlDataA%a2ter1/)ill(DataSet1)
4 Cerramos la ConeGiSn
SIlConnection1/Close()
4 Declaramos la 2ro2ie%a% "oJ 2ara recorrer
4 las 8ilas conteni%as en el DataSet
Dim "oJ
4 "ecorremos to%as las 8ilas - las tratamos
)or ach "oJ In DataSet1/1ables(0)/"oJs
1eGt,oG1/1eGt B= "oJ("SocioAI)")/1oString P 5b1ab P
"oJ(")echaAlI!iler") P 5bCr'8
AeGt
n% S!b
n% Class
Ahora nos queda nicamente ejecutar nuestra aplicacin para estudiar el resultado
final. Este es el que se puede ver en la figura 9.
jemplo en ejecucin del uso de componentes
Figura 9
Pese a todo lo que hemos visto, quizs se pregunte como es que en el caso del primer
ejemplo que hemos visto y en el que hemos declarado el uso de un Data*dapter sin
usar componentes, hemos tenido la obligatoriedad de aadir las referencias a los
nombres de espacio System.Data y System.Jml, mientras que en este segundo
ejemplo, no hemos hecho referencia a ellos.
En realidad nosotros no hemos hecho referencia a ellos, pero al insertar los
componentes dentro del formulario, el entorno Visual Basic 2005 Express se ha
342
encargado por nosotros de aadir esas referencias al proyecto, tal y como puede verse
en la figura 10.
3eferencias a2adidas autom>ticamente al trabajar con componentes de acceso a datos
Figura 10

343
%(dulo B ? Cap!tulo A
A. -nsertando datos a trav0s del obeto "ataAdapter
Hasta ahora, todos los ejemplos que hemos visto del objeto Data*dapter, han sido
ejemplos del uso de seleccin de datos, pero an no hemos visto como debemos
trabajar cuando realicemos otras acciones sobre la fuente de datos.
A continuacin, veremos como realizar acciones de actualizacin de datos, utilizando
para ello el objeto Data*dapter.
Becuerde3
%l DataSet permanece desconectado de la fuente de datos y si
reali.amos una modificaci<n o alteraci<n de los datos de un DataSet3
estos no son propagados a la fuente de datos. +ara ello3 el
Data*dapter debe recibir la orden 9ue 9ueramos ejecutar.


7C(mo se insertan datos con el obeto DataAdapter
Suponiendo que hemos recogido un conjunto de datos y que trabajando con el objeto
DataSet hemos realizado una insercin de datos y que a continuacin, queremos
propagar dicha insercin a la base de datos, deberemos hacer uso del mtodo Insert
del objeto Data*dapter.
El objeto Data*dapter se encargar de llamar al comando apropiado para cada una de
las filas que han sido modificadas en un determinado DataSet.
Esto lo realizar siempre a travs del mtodo ,pdate.


Trabaando con un eemplo
La mejor manera de ver esto es con un ejemplo que nos ayude a entender mejor
como funciona la insercin de datos a travs del objeto Data*dapter.
Tenga en cuenta adems, que la actualizacin y el borrado de datos funciona de la
misma manera.
Iniciaremos un nuevo proyecto de formulario Windows y en l insertamos los
componentes S9lConnection, S9lData*dapter, DataSet y S9lCommand.
Para el componente S9lConnection, estableceremos la propiedad ConnectionString con
el valor:
server=.;uid=sa;password=VisualBasic;database=MSDNVideo
A continuacin seleccionaremos el componente S9lData*dapter y modificaremos la
propiedad .elect"o))and > "onnection como vimos en el captulo anterior.
De la lista de posibles conexiones que le aparezca, seleccione la conexin
S9lConnectionH.
Finalmente, inserte un control Button y un control Data1rid#ie! en el formulario.
ste quedar como se indica en la figura 1.
344
(ormulario con los componentes y controles insertados en l
Figura 1
Finalmente, escribiremos el cdigo necesario para ejecutar nuestra aplicacin tal y
como queremos. Este es el que se detalla a continuacin:
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 stablecemos la ca%ena S]' a !tili&ar
SIlDataA%a2ter1/SelectComman%/Comman%1eGt = "S'C1 AI), Aombre,
A2elli%o1, A2elli%o2, 1ele8ono, mail, Direccion, Ci!%a%, ?ro5incia, C?
)"0H S0CI0S"
4 Abrimos la ConeGiSn
SIlConnection1/02en()
4 "ellenamos el DataSet con el conteni%o %e la instr!cciSn S]'
SIlDataA%a2ter1/)ill(DataSet1, "#em2lo")
4 Cerramos la ConeGiSn
SIlConnection1/Close()
345
4 Asociamos el control Data;ri%$ieJ al DataSet
Data;ri%$ieJ1/DataSo!rce = DataSet1/1ables("#em2lo")
n% S!b
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
4 Declaramos !n ob#eto Data"oJ 2ara
4 insertar en Rl los n!e5os %atos
Dim HiData"oJ As Data/Data"oJ
4 Creamos !na n!e5a 8ila en el DataSet
HiData"oJ = DataSet1/1ables("#em2lo")/AeJ"oJ()
4 Insertamos los %atos en el DataSet
HiData"oJ("AI)") = "222222"
HiData"oJ("Aombre") = "HarKa"
HiData"oJ("A2elli%o1") = "@!6re&"
HiData"oJ("A2elli%o2") = ")ern6n%e&"
HiData"oJ("1ele8ono") = "1112233"
HiData"oJ("mail") = "marKa\c!enta%email/com"
HiData"oJ("Direccion") = "CU )ern6n%e& %e los "Kos, NN"
HiData"oJ("Ci!%a%") = "$alla%oli%"
HiData"oJ("?ro5incia") = "$alla%oli%"
HiData"oJ("C?") = "11111"
DataSet1/1ables("#em2lo")/"oJs/A%%(HiData"oJ)
4 Si el DataSet tiene cambios ^
I8 DataSet1/HasChanges 1hen
4 In%icamos la instr!cciSn S]' corres2on%iente
SIlComman%1/Comman%1eGt = "IAS"1 IA10 S0CI0S(AI), Aombre,
A2elli%o1, A2elli%o2, 1ele8ono, mail, Direccion, Ci!%a%, ?ro5incia, C?)
$A'FS(\AI), \Aombre, \A2elli%o1, \A2elli%o2, \1ele8ono, \mail,
\Direccion, \Ci!%a%, \?ro5incia, \C?)"
4 stablecemos 2ara el coman%o,
4 la (coneGiSn) I!e !tili&aremos
SIlComman%1/Connection = SIlConnection1
346
4 'e in%icamos al DataA%a2ter, c!6l es el
4 coman%o %e inserciSn I!e !saremos
SIlDataA%a2ter1/InsertComman% = SIlComman%1
4 ATa%imos los 2ar6metros - coman%os corres2on%ientes
4 2ara ca%a cam2o a aTa%ir en la base %e %atos
SIlComman%1/?arameters/A%%("\AI)", Data/SIlDb1-2e/AChar, 10,
"AI)")
SIlComman%1/?arameters/A%%("\Aombre", Data/SIlDb1-2e/A$arChar, 50,
"Aombre")
SIlComman%1/?arameters/A%%("\A2elli%o1", Data/SIlDb1-2e/A$arChar,
50, "A2elli%o1")
SIlComman%1/?arameters/A%%("\A2elli%o2", Data/SIlDb1-2e/A$arChar,
50, "A2elli%o2")
SIlComman%1/?arameters/A%%("\1ele8ono", Data/SIlDb1-2e/A$arChar,
13, "1ele8ono")
SIlComman%1/?arameters/A%%("\mail", Data/SIlDb1-2e/A$arChar, 50,
"mail")
SIlComman%1/?arameters/A%%("\Direccion", Data/SIlDb1-2e/A$arChar,
100, "Direccion")
SIlComman%1/?arameters/A%%("\Ci!%a%", Data/SIlDb1-2e/A$arChar, 50,
"Ci!%a%")
SIlComman%1/?arameters/A%%("\?ro5incia", Data/SIlDb1-2e/A$arChar,
50, "?ro5incia")
SIlComman%1/?arameters/A%%("\C?", Data/SIlDb1-2e/AChar, 5, "C?")
4 Abrimos la coneGiSn
SIlConnection1/02en()
4 "eali&amos la inserciSn %e %atos %es%e el DataSet
4 a tra5Rs %el DataA%a2ter
SIlDataA%a2ter1/F2%ate(DataSet1, "#em2lo")
4 Cerramos la coneGiSn
SIlConnection1/Close()
4 In%icamos con !n mensa#e I!e la inserciSn
4 %e %atos se ha reali&a%o con RGito
Hessage,oG/ShoJ("Datos inserta%os correctamente")
n% I8
n% S!b
347
n% Class
Por ltimo, ejecute la aplicacin. Si todo ha ido correctamente, los datos habrn
quedado correctamente insertados en la base de datos.
Un ejemplo de nuestra aplicacin en ejecucin es la que puede verse en la figura 2.
Aplicacin de ejemplo de insercin de datos con DataAdapter y Data!et en ejecucin
Figura 2
Como vemos, el uso de Data*dapter en el caso de manipular datos, vara ligeramente.
Sin embargo, no es mucho ms complicado con la actualizacin y borrado de datos.
De hecho, la forma de actuar es la misma como veremos a continuacin.

348

%(dulo B ? Cap!tulo A
B. Actuali*ando datos a trav0s del obeto "ataAdapter
De la misma manera que hemos insertado datos en nuestra base de datos, debemos
hacer a la hora de actualizar los mismos.
Sobre la base del ejemplo anterior (componentes y controles), escriba o modifique el
siguiente cdigo:
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 stablecemos la ca%ena S]' a !tili&ar
SIlDataA%a2ter1/SelectComman%/Comman%1eGt = "S'C1 AI), Aombre,
A2elli%o1, A2elli%o2, 1ele8ono, mail, Direccion, Ci!%a%, ?ro5incia, C?
)"0H S0CI0S"
4 Abrimos la ConeGiSn
SIlConnection1/02en()
4 "ellenamos el DataSet con el conteni%o %e la instr!cciSn S]'
SIlDataA%a2ter1/)ill(DataSet1, "#em2lo")
4 Cerramos la ConeGiSn
SIlConnection1/Close()
4 Asociamos el control Data;ri%$ieJ al DataSet
Data;ri%$ieJ1/DataSo!rce = DataSet1/1ables("#em2lo")
n% S!b
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
4 n n!estro e#em2lo, sabemos I!e I!eremos mo%i8icar
4 la 8ila 2, col!mna . (to%os los elementos em2ie&an 2or 0)
DataSet1/1ables("#em2lo")/"oJs(1)(.) = "111223."
4 Si el DataSet tiene cambios ^
I8 DataSet1/HasChanges 1hen
349
4 In%icamos la instr!cciSn S]' corres2on%iente
SIlComman%1/Comman%1eGt = "F?DA1 S0CI0S S1 1ele8ono=\1ele8ono
<H" AI)=\AI)"
4 stablecemos 2ara el coman%o,
4 la (coneGiSn) I!e !tili&aremos
SIlComman%1/Connection = SIlConnection1
4 'e in%icamos al DataA%a2ter, c!6l es el
4 coman%o %e act!ali&aciSn I!e !saremos
SIlDataA%a2ter1/F2%ateComman% = SIlComman%1
4 ATa%imos los 2ar6metros - coman%os corres2on%ientes
4 2ara ca%a cam2o a act!ali&ar en la base %e %atos
SIlComman%1/?arameters/A%%("\AI)", Data/SIlDb1-2e/AChar, 10,
"AI)")
SIlComman%1/?arameters/A%%("\Aombre", Data/SIlDb1-2e/A$arChar, 50,
"Aombre")
SIlComman%1/?arameters/A%%("\A2elli%o1", Data/SIlDb1-2e/A$arChar,
50, "A2elli%o1")
SIlComman%1/?arameters/A%%("\A2elli%o2", Data/SIlDb1-2e/A$arChar,
50, "A2elli%o2")
SIlComman%1/?arameters/A%%("\1ele8ono", Data/SIlDb1-2e/A$arChar,
13, "1ele8ono")
SIlComman%1/?arameters/A%%("\mail", Data/SIlDb1-2e/A$arChar, 50,
"mail")
SIlComman%1/?arameters/A%%("\Direccion", Data/SIlDb1-2e/A$arChar,
100, "Direccion")
SIlComman%1/?arameters/A%%("\Ci!%a%", Data/SIlDb1-2e/A$arChar, 50,
"Ci!%a%")
SIlComman%1/?arameters/A%%("\?ro5incia", Data/SIlDb1-2e/A$arChar,
50, "?ro5incia")
SIlComman%1/?arameters/A%%("\C?", Data/SIlDb1-2e/AChar, 5, "C?")
4 Abrimos la coneGiSn
SIlConnection1/02en()
4 "eali&amos la act!ali&aciSn %e %atos %es%e
4 el DataSet a tra5Rs %el DataA%a2ter
SIlDataA%a2ter1/F2%ate(DataSet1, "#em2lo")
4 Cerramos la coneGiSn
350
SIlConnection1/Close()
4 In%icamos con !n mensa#e I!e la act!ali&aciSn
4 %e %atos se ha reali&a%o con RGito
Hessage,oG/ShoJ("Datos act!ali&a%os correctamente")
n% I8
n% S!b
n% Class
Nuestro ejemplo en ejecucin es el que se puede ver en la figura 1.
Aplicacin de ejemplo de actuali4acin de datos con DataAdapter y Data!et
Figura 1

351

%(dulo B ? Cap!tulo A
3. Eliminando datos a trav0s del obeto "ataAdapter
De igual forma sucede con la eliminacin de datos utilizando para ello el objeto
Data*dapter junto al objeto DataSet.
Utilizaremos nuevamente en este caso, la base del ejemplo anterior (componentes y
controles), y escribiremos el siguiente cdigo:
?!blic Class )orm1
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 stablecemos la ca%ena S]' a !tili&ar
SIlDataA%a2ter1/SelectComman%/Comman%1eGt = "S'C1 AI), Aombre,
A2elli%o1, A2elli%o2, 1ele8ono, mail, Direccion, Ci!%a%, ?ro5incia, C?
)"0H S0CI0S"
4 Abrimos la ConeGiSn
SIlConnection1/02en()
4 "ellenamos el DataSet con el conteni%o %e la instr!cciSn S]'
SIlDataA%a2ter1/)ill(DataSet1, "#em2lo")
4 Cerramos la ConeGiSn
352
SIlConnection1/Close()
4 Asociamos el control Data;ri%$ieJ al DataSet
Data;ri%$ieJ1/DataSo!rce = DataSet1/1ables("#em2lo")
n% S!b
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
4 n n!estro e#em2lo, sabemos I!e I!eremos eliminar
4 la 8ila 2 (to%os los elementos em2ie&an 2or 0)
4 2or lo I!e la 8ila 2 es aI!K la 1
DataSet1/1ables("#em2lo")/"oJs(1)/Delete()
4 Si el DataSet tiene cambios ^
I8 DataSet1/HasChanges 1hen
4 In%icamos la instr!cciSn S]' corres2on%iente
SIlComman%1/Comman%1eGt = "D'1 S0CI0S <H" AI)=\AI)"
4 stablecemos 2ara el coman%o,
4 la (coneGiSn) I!e !tili&aremos
SIlComman%1/Connection = SIlConnection1
4 'e in%icamos al DataA%a2ter, c!6l es el
4 coman%o %e eliminaciSn I!e !saremos
SIlDataA%a2ter1/DeleteComman% = SIlComman%1
4 ATa%imos los 2ar6metros - coman%os corres2on%ientes
4 2ara ca%a cam2o a act!ali&ar en la base %e %atos
SIlComman%1/?arameters/A%%("\AI)", Data/SIlDb1-2e/AChar, 10,
"AI)")
SIlComman%1/?arameters/A%%("\Aombre", Data/SIlDb1-2e/A$arChar, 50,
"Aombre")
SIlComman%1/?arameters/A%%("\A2elli%o1", Data/SIlDb1-2e/A$arChar,
50, "A2elli%o1")
SIlComman%1/?arameters/A%%("\A2elli%o2", Data/SIlDb1-2e/A$arChar,
50, "A2elli%o2")
SIlComman%1/?arameters/A%%("\1ele8ono", Data/SIlDb1-2e/A$arChar,
13, "1ele8ono")
353
SIlComman%1/?arameters/A%%("\mail", Data/SIlDb1-2e/A$arChar, 50,
"mail")
SIlComman%1/?arameters/A%%("\Direccion", Data/SIlDb1-2e/A$arChar,
100, "Direccion")
SIlComman%1/?arameters/A%%("\Ci!%a%", Data/SIlDb1-2e/A$arChar, 50,
"Ci!%a%")
SIlComman%1/?arameters/A%%("\?ro5incia", Data/SIlDb1-2e/A$arChar,
50, "?ro5incia")
SIlComman%1/?arameters/A%%("\C?", Data/SIlDb1-2e/AChar, 5, "C?")
4 Abrimos la coneGiSn
SIlConnection1/02en()
4 "eali&amos la eliminaciSn %e %atos %es%e
4 el DataSet a tra5Rs %el DataA%a2ter
SIlDataA%a2ter1/F2%ate(DataSet1, "#em2lo")
4 Cerramos la coneGiSn
SIlConnection1/Close()
4 In%icamos con !n mensa#e I!e la eliminaciSn
4 %e %atos se ha reali&a%o con RGito
Hessage,oG/ShoJ("Datos elimina%os correctamente")
n% I8
n% S!b
n% Class
Nuestro ejemplo en ejecucin es el que se puede ver en la figura 1.
354
Aplicacin de ejemplo de eliminacin de datos con DataAdapter y Data!et
Figura 1

-ntroducci(n
Otra particularidad de .NET a la hora de trabajar con fuentes de datos y con los
componentes y controles que nos permiten acceder a ellas, es el trabajo con dos tipos
de DataSets.
Sin quererlo ya hemos visto como trabajar con uno de ellos, me refiero a los DataSets
no tipados, sin embargo, hay otro tipo de DataSet diferente denominado as, DataSet
tipado.
355
En qu consiste un DataSet tipado y como utilizarlos, es lo que vamos a ver a
continuacin.
%(dulo B ? Cap!tulo B

1. Qu son los DataSets tipados?
2. Generando nuestros DataSets tipados
3. Generando un DataSet tipado con Visual Basic 2005 Express
4. Generando un DataSet tipado con la lnea de comandos
5. Usando los DataSets tipados


%(dulo B ? Cap!tulo B
@. 78u0 son los "ataSets tipados9
De forma genrica, podemos definir como DataSet tipado, a aquel DataSet que posee
un esquema de datos, a diferencia del DataSet no tipado, que no necesita de ese
esquema.
Respecto a los DataSet tipados, diremos que en el entorno de desarrollo, encontramos
muchas utilidades y herramientas que nos facilitan el trabajo de este tipo de DataSets.
Inclusive, el propio SDK posee herramientas de comandos que nos permite y nos
facilita la preparacin para trabajar con DataSets tipados.
El esquema al que un DataSet tipado hace referencia, es un documento XML.
Se trata de un documento XML con extensin .&sd.
Trabajar con un esquema en lugar de trabajar con una tabla directamente, es mucho
ms gil, fcil, rpido y seguro, como veremos ms adelante.


356
C(mo trabaar con un "ataSet tipado
Evidentemente, lo que tenemos que tener claro y tomarlo as, como punto de partida,
es que si queremos trabajar con un DataSet tipado, tenemos que crear su
correspondiente esquema XML.
Esto lo podemos hacer con una herramienta externa, manualmente, o con las
herramientas que el entorno de desarrollo de Visual Basic 2005 Express o el propio
SDK nos ofrece.
En nuestro caso, ser estas ltimas acciones lo que usaremos. Obviamente, hacerlo
manualmente es en mi opinin para fri6is, mxime cuando sabemos que tenemos
herramientas que nos facilitan su creacin y nos ahorran mucho tiempo y recursos.
Cuando tengamos ya creado el esquema XML, deberamos generar la clase del
DataSet, algo que a estas alturas, ya lo tenemos dominado.
En uno de los mtodos de creacin del esquema, el entorno hace ese trabajo por
nosotros, en el otro, que es un proceso ms manual como veremos, deberamos crear
esa clase con posterioridad, pero an as, esto ltimo no lo veremos con excesiva
profundidad.


78u0 ventaas nos aportan los "ataSets tipados9
Ya hemos enumerado algunas de ellas, rapidez, seguridad, agilidad, fcilidad de
trabajo, todo ello aplicable a los datos.
An as, existen muchas ms razones para interesarnos por los DataSets tipados.
A travs de los DataSets tipados, podemos realizar acciones que comunmente son
costosas, de manera rpida y sencilla.
Acciones como actualizacin de datos, modificacin, insercin o eliminacin de datos,
o bsquedas de datos, son algunas de las acciones que en apenas un par de lneas de
cdigo, estarn resueltas gracias al uso de DataSet tipados.
Esto lo veremos ms adelante con los ejemplos de este captulo.
Otras acciones adicionales vinculadas con los DataSets tipados son la posibilidad de
filtrar datos, ordenar los datos, y trabajar con datos jerrquicos y relaciones de datos.
Una diferencia notable entre los DataSets no tipados y los DataSets tipados, es que los
primeros no saben ni tienen conocimiento alguno de lo que almacenan.
Los segundos tienen cierta dosis de inteligencia y conocen el tipo de datos que
almacena dentro.
Adems de todo esto, el acceso a los datos que guarda un DataSet tipado, as como la
manipulacin de los mismos, es mucho ms simple y requiere menos cdigo, haciendo
que el acceso a los datos y el mantenimiento de la aplicacin sea ms cmoda y
sencilla.
357

%(dulo B ? Cap!tulo B
1. 5enerando nuestros "ataSets tipados
Dentro de Visual Basic 2005 Express y de .NET en general, tenemos varias formas de
generar nuestros propios DataSets tipados.
Una de las formas de generar DataSets tipados es utilizando el entorno de desarrollo
rpido Visual Basic 2005 E;press.
La otra es utilizando la herramienta LS/.e;e que encontraremos en el directorio SDK
del entorno.
Ambas formas, las veremos a continuacin.


"iagrama de datos
Antes de continuar, repasaremos el diagrama de datos con el cul vamos a trabajar.
Este es el que se muestra en la figura 1.
358
Dia"rama de datos con el que vamos a trabajar
Figura 1
Este diagrama nos ayudar a interpretar los datos y a trabajar con ellos, en los
ejemplos que veremos a continuacin.
A continuacin, veremos como generar DataSets tipados desde el entorno de trabajo
rpido, es decir #isual Basic 2BBC %&press, y desde la lnea de comandos.

359

%(dulo B ? Cap!tulo B
A. 5enerando un "ataSet tipado con Visual .asic 1223
E;press
La forma ms rpida para generar DataSets tipados es utilizando las herramientas
automticas del entorno #isual Basic 2BBC %&press.
A continuacin veremos como hacer esto de manera rpida y sencilla.


:sando el entorno de desarrollo r&pido Visual .asic 1223 E;press
Cree un nuevo proyecto de *plicaci<n para 4indo!s y haga clic con el botn derecho
del ratn sobre la ventana %&plorador de soluciones, y del men emergente,
seleccione la opcin 4're'ar 6 Nuevo elemento..., tal y como se muestra en la
figura 1.
360
Men? para a"re"ar un elemento al proyecto
Figura 1
Aparecer entonces una ventana de *gregar nueo elemento, dentro de la cul
seleccionaremos la plantilla de -on(unto de datos, tal y como se muestra en la figura
2.
361
&entana para a"re"ar un nuevo elemento al proyecto
Figura 2
Haga clic en el botn 4're'ar.
La plantilla del esquema del DataSet, tendr un aspecto similar al que se muestra en
la figura 3.
362
squema por defecto del Data!et en &isual #asic ,++- 5press
Figura 3
El siguiente paso que deberemos abordar, ser la de aadir al esquema, las tablas que
queremos que formen parte del DataSet tipado.
Para hacer esto, abra la ventana E;plorador de #ase de datos y seleccione la base
de datos de prueba.
Pulse sobre la tabla .ocios y arrstrela sobre el esquema del DataSet como se indica
en la figura 4.
363
Arrastramos la tabla !ocios sobre el esquema del Data!et
Figura 4
El esquema de la tabla quedar entonces aadido a la aplicacin, tal y como se indica
en la figura 5.
squema de la tabla !ocios a2adido al entorno de trabajo
Figura 5
En este punto, tendremos listo nuestro DataSet tipado, pero an no tendremos una
clase o cdigo asociado al DataSet tipado.
An no lo hemos dicho, pero en este punto, #isual Basic 2BBC %&press ha generado
para nosotros, el cdigo relacionado con el DataSet tipado creado.
Este cdigo, est dentro del directorio de la aplicacin, y puede ser accedido a l
pulsando el botn de la ventana E;plorador de soluciones y representado por el
siguiente icono
Esto es lo que se representa en la figura 6.
:pcin de mostrar todos los arc%ivos
Figura 6
364
En este punto, veremos que los archivos relacionados con nuestro proyecto y en el
caso del elemento DataSetH.&sd, son los que se detallan en la figura 7.
Arc%ivos del proyecto
Figura 7
Observamos que el archivo DataSetH.Designer.b depende del archivo DataSetH.&sd, y
es el que contiene el cdigo necesario para utilizar el DataSet tipado.
De hecho, si vemos el cdigo generado por #isual Basic 2BBC %&press, observaremos
que coincide con el que se detalla a continuacin:
4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCC
4 (a!toCgenerate%*
4 Fna herramienta generS este cS%igo/
4 $ersiSn %el motor en tiem2o %e e#ec!ciSnD2/0/50215/..
4
4 'os cambios en este archi5o 2o%rKan ca!sar !n com2ortamiento
incorrecto - se 2er%er6n si
4 el cS%igo se 5!el5e a generar/
4 (Va!toCgenerate%*
4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCC
365
02tion Strict 088
02tion G2licit 0n
Im2orts S-stem
(Seriali&able(), +
S-stem/Com2onentHo%el/DesignerCategor-Attrib!te("co%e"), +
S-stem/Com2onentHo%el/1oolboGItem(tr!e), +

S-stem/Lml/Seriali&ation/LmlSchema?ro5i%erAttrib!te(";et1-2e%DataSetSchema"
), +
S-stem/Lml/Seriali&ation/Lml"ootAttrib!te("DataSet1"), +
S-stem/Com2onentHo%el/Design/Hel2Ze-Jor%Attrib!te("5s/%ata/DataSet"), +

S-stem/Diagnostics/Co%eAnal-sis/S!22ressHessageAttrib!te("Hicroso8t/Fsage",
"CA22.0DIm2lementISeriali&ableCorrectl-")* +
?artial ?!blic Class DataSet1
Inherits S-stem/Data/DataSet

?ri5ate tableSocios As SociosData1able

?ri5ate +schemaSeriali&ationHo%e As S-stem/Data/SchemaSeriali&ationHo%e
= S-stem/Data/SchemaSeriali&ationHo%e/Incl!%eSchema


(S-stem/Diagnostics/Co%eAnal-sis/S!22ressHessageAttrib!te("Hicroso8t/Fsage"
, "CA221.DDoAotCall05erri%ableHetho%sInConstr!ctors")* +
?!blic S!b AeJ()
H-,ase/AeJ
He/,eginInit
He/InitClass
Dim schemaChange%Han%ler As
S-stem/Com2onentHo%el/CollectionChange5entHan%ler = A%%ress08
He/SchemaChange%
A%%Han%ler H-,ase/1ables/CollectionChange%, schemaChange%Han%ler
366
A%%Han%ler H-,ase/"elations/CollectionChange%, schemaChange%Han%ler
He/n%Init
n% S!b


(S-stem/Diagnostics/Co%eAnal-sis/S!22ressHessageAttrib!te("Hicroso8t/Fsage"
, "CA221.DDoAotCall05erri%ableHetho%sInConstr!ctors")* +
?rotecte% S!b AeJ(,-$al in8o As
S-stem/"!ntime/Seriali&ation/Seriali&ationIn8o, ,-$al conteGt As
S-stem/"!ntime/Seriali&ation/StreamingConteGt)
H-,ase/AeJ(in8o, conteGt)
I8 (He/Is,inar-Seriali&e%(in8o, conteGt) = tr!e) 1hen
He/Init$ars(8alse)
Dim schemaChange%Han%ler1 As
S-stem/Com2onentHo%el/CollectionChange5entHan%ler = A%%ress08
He/SchemaChange%
A%%Han%ler He/1ables/CollectionChange%, schemaChange%Han%ler1
A%%Han%ler He/"elations/CollectionChange%, schemaChange%Han%ler1
"et!rn
n% I8
Dim strSchema As String = C1-2e(in8o/;et$al!e("LmlSchema",
;et1-2e(String)),String)
I8 (He/DetermineSchemaSeriali&ationHo%e(in8o, conteGt) =
S-stem/Data/SchemaSeriali&ationHo%e/Incl!%eSchema) 1hen
Dim %s As S-stem/Data/DataSet = AeJ S-stem/Data/DataSet
%s/"ea%LmlSchema(AeJ S-stem/Lml/Lml1eGt"ea%er(AeJ
S-stem/I0/String"ea%er(strSchema)))
I8 (Aot (%s/1ables("Socios")) Is Aothing) 1hen
H-,ase/1ables/A%%(AeJ SociosData1able(%s/1ables("Socios")))
n% I8
He/DataSetAame = %s/DataSetAame
He/?re8iG = %s/?re8iG
He/Aames2ace = %s/Aames2ace
He/'ocale = %s/'ocale
He/CaseSensiti5e = %s/CaseSensiti5e
He/n8orceConstraints = %s/n8orceConstraints
367
He/Herge(%s, 8alse, S-stem/Data/HissingSchemaAction/A%%)
He/Init$ars
lse
He/"ea%LmlSchema(AeJ S-stem/Lml/Lml1eGt"ea%er(AeJ
S-stem/I0/String"ea%er(strSchema)))
n% I8
He/;etSeriali&ationData(in8o, conteGt)
Dim schemaChange%Han%ler As
S-stem/Com2onentHo%el/CollectionChange5entHan%ler = A%%ress08
He/SchemaChange%
A%%Han%ler H-,ase/1ables/CollectionChange%, schemaChange%Han%ler
A%%Han%ler He/"elations/CollectionChange%, schemaChange%Han%ler
n% S!b

(S-stem/Com2onentHo%el/,roJsable(8alse), +

S-stem/Com2onentHo%el/DesignerSeriali&ation$isibilit-(S-stem/Com2onentHo%el
/DesignerSeriali&ation$isibilit-/Content)* +
?!blic "ea%0nl- ?ro2ert- Socios() As SociosData1able
;et
"et!rn He/tableSocios
n% ;et
n% ?ro2ert-

?!blic 05erri%es ?ro2ert- SchemaSeriali&ationHo%e() As
S-stem/Data/SchemaSeriali&ationHo%e
;et
"et!rn He/+schemaSeriali&ationHo%e
n% ;et
Set
He/+schemaSeriali&ationHo%e = 5al!e
n% Set
n% ?ro2ert-

368

(S-stem/Com2onentHo%el/DesignerSeriali&ation$isibilit-Attrib!te(S-stem/Com2
onentHo%el/DesignerSeriali&ation$isibilit-/Hi%%en)* +
?!blic Sha%oJs "ea%0nl- ?ro2ert- 1ables() As
S-stem/Data/Data1ableCollection
;et
"et!rn H-,ase/1ables
n% ;et
n% ?ro2ert-


(S-stem/Com2onentHo%el/DesignerSeriali&ation$isibilit-Attrib!te(S-stem/Com2
onentHo%el/DesignerSeriali&ation$isibilit-/Hi%%en)* +
?!blic Sha%oJs "ea%0nl- ?ro2ert- "elations() As
S-stem/Data/Data"elationCollection
;et
"et!rn H-,ase/"elations
n% ;et
n% ?ro2ert-

(S-stem/Com2onentHo%el/De8a!lt$al!eAttrib!te(tr!e)* +
?!blic Sha%oJs ?ro2ert- n8orceConstraints() As ,oolean
;et
"et!rn H-,ase/n8orceConstraints
n% ;et
Set
H-,ase/n8orceConstraints = 5al!e
n% Set
n% ?ro2ert-

?rotecte% 05erri%es S!b Initiali&eDeri5e%DataSet()
He/,eginInit
He/InitClass
He/n%Init
369
n% S!b

?!blic 05erri%es )!nction Clone() As S-stem/Data/DataSet
Dim cln As DataSet1 = C1-2e(H-,ase/Clone,DataSet1)
cln/Init$ars
"et!rn cln
n% )!nction

?rotecte% 05erri%es )!nction Sho!l%Seriali&e1ables() As ,oolean
"et!rn 8alse
n% )!nction

?rotecte% 05erri%es )!nction Sho!l%Seriali&e"elations() As ,oolean
"et!rn 8alse
n% )!nction

?rotecte% 05erri%es S!b "ea%LmlSeriali&able(,-$al rea%er As
S-stem/Lml/Lml"ea%er)
I8 (He/DetermineSchemaSeriali&ationHo%e(rea%er) =
S-stem/Data/SchemaSeriali&ationHo%e/Incl!%eSchema) 1hen
He/"eset
Dim %s As S-stem/Data/DataSet = AeJ S-stem/Data/DataSet
%s/"ea%Lml(rea%er)
I8 (Aot (%s/1ables("Socios")) Is Aothing) 1hen
H-,ase/1ables/A%%(AeJ SociosData1able(%s/1ables("Socios")))
n% I8
He/DataSetAame = %s/DataSetAame
He/?re8iG = %s/?re8iG
He/Aames2ace = %s/Aames2ace
He/'ocale = %s/'ocale
He/CaseSensiti5e = %s/CaseSensiti5e
He/n8orceConstraints = %s/n8orceConstraints
370
He/Herge(%s, 8alse, S-stem/Data/HissingSchemaAction/A%%)
He/Init$ars
lse
He/"ea%Lml(rea%er)
He/Init$ars
n% I8
n% S!b

?rotecte% 05erri%es )!nction ;etSchemaSeriali&able() As
S-stem/Lml/Schema/LmlSchema
Dim stream As S-stem/I0/Hemor-Stream = AeJ S-stem/I0/Hemor-Stream
He/<riteLmlSchema(AeJ S-stem/Lml/Lml1eGt<riter(stream, Aothing))
stream/?osition = 0
"et!rn S-stem/Lml/Schema/LmlSchema/"ea%(AeJ
S-stem/Lml/Lml1eGt"ea%er(stream), Aothing)
n% )!nction

)rien% 05erloa%s S!b Init$ars()
He/Init$ars(tr!e)
n% S!b

)rien% 05erloa%s S!b Init$ars(,-$al init1able As ,oolean)
He/tableSocios = C1-2e(H-,ase/1ables("Socios"),SociosData1able)
I8 (init1able = tr!e) 1hen
I8 (Aot (He/tableSocios) Is Aothing) 1hen
He/tableSocios/Init$ars
n% I8
n% I8
n% S!b

?ri5ate S!b InitClass()
He/DataSetAame = "DataSet1"
371
He/?re8iG = ""
He/Aames2ace = "htt2D"VVtem2!ri/orgVDataSet1/Gs%"
He/n8orceConstraints = tr!e
He/tableSocios = AeJ SociosData1able
H-,ase/1ables/A%%(He/tableSocios)
n% S!b

?ri5ate )!nction Sho!l%Seriali&eSocios() As ,oolean
"et!rn 8alse
n% )!nction

?ri5ate S!b SchemaChange%(,-$al sen%er As 0b#ect, ,-$al e As
S-stem/Com2onentHo%el/CollectionChange5entArgs)
I8 (e/Action = S-stem/Com2onentHo%el/CollectionChangeAction/"emo5e)
1hen
He/Init$ars
n% I8
n% S!b

?!blic Share% )!nction ;et1-2e%DataSetSchema(,-$al Gs As
S-stem/Lml/Schema/LmlSchemaSet) As S-stem/Lml/Schema/LmlSchemaCom2leG1-2e
Dim %s As DataSet1 = AeJ DataSet1
Dim t-2e As S-stem/Lml/Schema/LmlSchemaCom2leG1-2e = AeJ
S-stem/Lml/Schema/LmlSchemaCom2leG1-2e
Dim seI!ence As S-stem/Lml/Schema/LmlSchemaSeI!ence = AeJ
S-stem/Lml/Schema/LmlSchemaSeI!ence
Gs/A%%(%s/;etSchemaSeriali&able)
Dim an- As S-stem/Lml/Schema/LmlSchemaAn- = AeJ
S-stem/Lml/Schema/LmlSchemaAn-
an-/Aames2ace = %s/Aames2ace
seI!ence/Items/A%%(an-)
t-2e/?article = seI!ence
"et!rn t-2e
n% )!nction
372

?!blic Delegate S!b Socios"oJChange5entHan%ler(,-$al sen%er As 0b#ect,
,-$al e As Socios"oJChange5ent)

(S-stem/Seriali&able(), +

S-stem/Lml/Seriali&ation/LmlSchema?ro5i%erAttrib!te(";et1-2e%1ableSchema")*
+
?artial ?!blic Class SociosData1able
Inherits S-stem/Data/Data1able
Im2lements S-stem/Collections/In!merable

?ri5ate col!mnAI) As S-stem/Data/DataCol!mn

?ri5ate col!mnAombre As S-stem/Data/DataCol!mn

?ri5ate col!mnA2elli%o1 As S-stem/Data/DataCol!mn

?ri5ate col!mnA2elli%o2 As S-stem/Data/DataCol!mn

?ri5ate col!mn1ele8ono As S-stem/Data/DataCol!mn

?ri5ate col!mnmail As S-stem/Data/DataCol!mn

?ri5ate col!mnDireccion As S-stem/Data/DataCol!mn

?ri5ate col!mnCi!%a% As S-stem/Data/DataCol!mn

?ri5ate col!mn?ro5incia As S-stem/Data/DataCol!mn

?ri5ate col!mnC? As S-stem/Data/DataCol!mn

373
?!blic S!b AeJ()
H-,ase/AeJ
He/1ableAame = "Socios"
He/,eginInit
He/InitClass
He/n%Init
n% S!b

)rien% S!b AeJ(,-$al table As S-stem/Data/Data1able)
H-,ase/AeJ
He/1ableAame = table/1ableAame
I8 (table/CaseSensiti5e (* table/DataSet/CaseSensiti5e) 1hen
He/CaseSensiti5e = table/CaseSensiti5e
n% I8
I8 (table/'ocale/1oString (* table/DataSet/'ocale/1oString) 1hen
He/'ocale = table/'ocale
n% I8
I8 (table/Aames2ace (* table/DataSet/Aames2ace) 1hen
He/Aames2ace = table/Aames2ace
n% I8
He/?re8iG = table/?re8iG
He/Hinim!mCa2acit- = table/Hinim!mCa2acit-
n% S!b

?rotecte% S!b AeJ(,-$al in8o As
S-stem/"!ntime/Seriali&ation/Seriali&ationIn8o, ,-$al conteGt As
S-stem/"!ntime/Seriali&ation/StreamingConteGt)
H-,ase/AeJ(in8o, conteGt)
He/Init$ars
n% S!b

?!blic "ea%0nl- ?ro2ert- AI)Col!mn() As S-stem/Data/DataCol!mn
374
;et
"et!rn He/col!mnAI)
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- AombreCol!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnAombre
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- A2elli%o1Col!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnA2elli%o1
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- A2elli%o2Col!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnA2elli%o2
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- 1ele8onoCol!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mn1ele8ono
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- mailCol!mn() As S-stem/Data/DataCol!mn
375
;et
"et!rn He/col!mnmail
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- DireccionCol!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnDireccion
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- Ci!%a%Col!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnCi!%a%
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- ?ro5inciaCol!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mn?ro5incia
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- C?Col!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnC?
n% ;et
n% ?ro2ert-

(S-stem/Com2onentHo%el/,roJsable(8alse)* +
376
?!blic "ea%0nl- ?ro2ert- Co!nt() As Integer
;et
"et!rn He/"oJs/Co!nt
n% ;et
n% ?ro2ert-

?!blic De8a!lt "ea%0nl- ?ro2ert- Item(,-$al in%eG As Integer) As
Socios"oJ
;et
"et!rn C1-2e(He/"oJs(in%eG),Socios"oJ)
n% ;et
n% ?ro2ert-

?!blic 5ent Socios"oJChange% As Socios"oJChange5entHan%ler

?!blic 5ent Socios"oJChanging As Socios"oJChange5entHan%ler

?!blic 5ent Socios"oJDelete% As Socios"oJChange5entHan%ler

?!blic 5ent Socios"oJDeleting As Socios"oJChange5entHan%ler

?!blic 05erloa%s S!b A%%Socios"oJ(,-$al roJ As Socios"oJ)
He/"oJs/A%%(roJ)
n% S!b

?!blic 05erloa%s )!nction A%%Socios"oJ(,-$al AI) As String, ,-$al
Aombre As String, ,-$al A2elli%o1 As String, ,-$al A2elli%o2 As String,
,-$al 1ele8ono As String, ,-$al mail As String, ,-$al Direccion As String,
,-$al Ci!%a% As String, ,-$al ?ro5incia As String, ,-$al C? As String) As
Socios"oJ
Dim roJSocios"oJ As Socios"oJ = C1-2e(He/AeJ"oJ,Socios"oJ)
roJSocios"oJ/ItemArra- = AeJ 0b#ect() =AI), Aombre, A2elli%o1,
A2elli%o2, 1ele8ono, mail, Direccion, Ci!%a%, ?ro5incia, C?>
He/"oJs/A%%(roJSocios"oJ)
377
"et!rn roJSocios"oJ
n% )!nction

?!blic )!nction )in%,-AI)(,-$al AI) As String) As Socios"oJ
"et!rn C1-2e(He/"oJs/)in%(AeJ 0b#ect() =AI)>),Socios"oJ)
n% )!nction

?!blic 05erri%able )!nction ;etn!merator() As
S-stem/Collections/In!merator Im2lements
S-stem/Collections/In!merable/;etn!merator
"et!rn He/"oJs/;etn!merator
n% )!nction

?!blic 05erri%es )!nction Clone() As S-stem/Data/Data1able
Dim cln As SociosData1able = C1-2e(H-,ase/Clone,SociosData1able)
cln/Init$ars
"et!rn cln
n% )!nction

?rotecte% 05erri%es )!nction CreateInstance() As
S-stem/Data/Data1able
"et!rn AeJ SociosData1able
n% )!nction

)rien% S!b Init$ars()
He/col!mnAI) = H-,ase/Col!mns("AI)")
He/col!mnAombre = H-,ase/Col!mns("Aombre")
He/col!mnA2elli%o1 = H-,ase/Col!mns("A2elli%o1")
He/col!mnA2elli%o2 = H-,ase/Col!mns("A2elli%o2")
He/col!mn1ele8ono = H-,ase/Col!mns("1ele8ono")
He/col!mnmail = H-,ase/Col!mns("mail")
He/col!mnDireccion = H-,ase/Col!mns("Direccion")
378
He/col!mnCi!%a% = H-,ase/Col!mns("Ci!%a%")
He/col!mn?ro5incia = H-,ase/Col!mns("?ro5incia")
He/col!mnC? = H-,ase/Col!mns("C?")
n% S!b

?ri5ate S!b InitClass()
He/col!mnAI) = AeJ S-stem/Data/DataCol!mn("AI)", ;et1-2e(String),
Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnAI))
He/col!mnAombre = AeJ S-stem/Data/DataCol!mn("Aombre",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnAombre)
He/col!mnA2elli%o1 = AeJ S-stem/Data/DataCol!mn("A2elli%o1",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnA2elli%o1)
He/col!mnA2elli%o2 = AeJ S-stem/Data/DataCol!mn("A2elli%o2",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnA2elli%o2)
He/col!mn1ele8ono = AeJ S-stem/Data/DataCol!mn("1ele8ono",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mn1ele8ono)
He/col!mnmail = AeJ S-stem/Data/DataCol!mn("mail",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnmail)
He/col!mnDireccion = AeJ S-stem/Data/DataCol!mn("Direccion",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnDireccion)
He/col!mnCi!%a% = AeJ S-stem/Data/DataCol!mn("Ci!%a%",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnCi!%a%)
He/col!mn?ro5incia = AeJ S-stem/Data/DataCol!mn("?ro5incia",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mn?ro5incia)
He/col!mnC? = AeJ S-stem/Data/DataCol!mn("C?", ;et1-2e(String),
Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnC?)
379
He/Constraints/A%%(AeJ S-stem/Data/FniI!eConstraint("Constraint1",
AeJ S-stem/Data/DataCol!mn() =He/col!mnAI)>, tr!e))
He/col!mnAI)/AlloJD,A!ll = 8alse
He/col!mnAI)/FniI!e = tr!e
He/col!mnAI)/HaG'ength = 10
He/col!mnAombre/HaG'ength = 50
He/col!mnA2elli%o1/HaG'ength = 50
He/col!mnA2elli%o2/HaG'ength = 50
He/col!mn1ele8ono/HaG'ength = 13
He/col!mnmail/HaG'ength = 50
He/col!mnDireccion/HaG'ength = 100
He/col!mnCi!%a%/HaG'ength = 50
He/col!mn?ro5incia/HaG'ength = 50
He/col!mnC?/HaG'ength = 5
He/'ocale = AeJ S-stem/;lobali&ation/C!lt!reIn8o("esCS")
n% S!b

?!blic )!nction AeJSocios"oJ() As Socios"oJ
"et!rn C1-2e(He/AeJ"oJ,Socios"oJ)
n% )!nction

?rotecte% 05erri%es )!nction AeJ"oJ)rom,!il%er(,-$al b!il%er As
S-stem/Data/Data"oJ,!il%er) As S-stem/Data/Data"oJ
"et!rn AeJ Socios"oJ(b!il%er)
n% )!nction

?rotecte% 05erri%es )!nction ;et"oJ1-2e() As S-stem/1-2e
"et!rn ;et1-2e(Socios"oJ)
n% )!nction

?rotecte% 05erri%es S!b 0n"oJChange%(,-$al e As
S-stem/Data/Data"oJChange5entArgs)
380
H-,ase/0n"oJChange%(e)
I8 (Aot (He/Socios"oJChange%5ent) Is Aothing) 1hen
"aise5ent Socios"oJChange%(He, AeJ
Socios"oJChange5ent(C1-2e(e/"oJ,Socios"oJ), e/Action))
n% I8
n% S!b

?rotecte% 05erri%es S!b 0n"oJChanging(,-$al e As
S-stem/Data/Data"oJChange5entArgs)
H-,ase/0n"oJChanging(e)
I8 (Aot (He/Socios"oJChanging5ent) Is Aothing) 1hen
"aise5ent Socios"oJChanging(He, AeJ
Socios"oJChange5ent(C1-2e(e/"oJ,Socios"oJ), e/Action))
n% I8
n% S!b

?rotecte% 05erri%es S!b 0n"oJDelete%(,-$al e As
S-stem/Data/Data"oJChange5entArgs)
H-,ase/0n"oJDelete%(e)
I8 (Aot (He/Socios"oJDelete%5ent) Is Aothing) 1hen
"aise5ent Socios"oJDelete%(He, AeJ
Socios"oJChange5ent(C1-2e(e/"oJ,Socios"oJ), e/Action))
n% I8
n% S!b

?rotecte% 05erri%es S!b 0n"oJDeleting(,-$al e As
S-stem/Data/Data"oJChange5entArgs)
H-,ase/0n"oJDeleting(e)
I8 (Aot (He/Socios"oJDeleting5ent) Is Aothing) 1hen
"aise5ent Socios"oJDeleting(He, AeJ
Socios"oJChange5ent(C1-2e(e/"oJ,Socios"oJ), e/Action))
n% I8
n% S!b

381
?!blic S!b "emo5eSocios"oJ(,-$al roJ As Socios"oJ)
He/"oJs/"emo5e(roJ)
n% S!b

?!blic Share% )!nction ;et1-2e%1ableSchema(,-$al Gs As
S-stem/Lml/Schema/LmlSchemaSet) As S-stem/Lml/Schema/LmlSchemaCom2leG1-2e
Dim t-2e As S-stem/Lml/Schema/LmlSchemaCom2leG1-2e = AeJ
S-stem/Lml/Schema/LmlSchemaCom2leG1-2e
Dim seI!ence As S-stem/Lml/Schema/LmlSchemaSeI!ence = AeJ
S-stem/Lml/Schema/LmlSchemaSeI!ence
Dim %s As DataSet1 = AeJ DataSet1
Gs/A%%(%s/;etSchemaSeriali&able)
Dim an-1 As S-stem/Lml/Schema/LmlSchemaAn- = AeJ
S-stem/Lml/Schema/LmlSchemaAn-
an-1/Aames2ace = "htt2D"VVJJJ/J3/orgV2001VLH'Schema"
an-1/Hin0cc!rs = AeJ Decimal(0)
an-1/HaG0cc!rs = Decimal/HaG$al!e
an-1/?rocessContents =
S-stem/Lml/Schema/LmlSchemaContent?rocessing/'aG
seI!ence/Items/A%%(an-1)
Dim an-2 As S-stem/Lml/Schema/LmlSchemaAn- = AeJ
S-stem/Lml/Schema/LmlSchemaAn-
an-2/Aames2ace = "!rnDschemasCmicroso8tCcomDGmlC%i88gramC51"
an-2/Hin0cc!rs = AeJ Decimal(1)
an-2/?rocessContents =
S-stem/Lml/Schema/LmlSchemaContent?rocessing/'aG
seI!ence/Items/A%%(an-2)
Dim attrib!te1 As S-stem/Lml/Schema/LmlSchemaAttrib!te = AeJ
S-stem/Lml/Schema/LmlSchemaAttrib!te
attrib!te1/Aame = "names2ace"
attrib!te1/)iGe%$al!e = %s/Aames2ace
t-2e/Attrib!tes/A%%(attrib!te1)
Dim attrib!te2 As S-stem/Lml/Schema/LmlSchemaAttrib!te = AeJ
S-stem/Lml/Schema/LmlSchemaAttrib!te
attrib!te2/Aame = "table1-2eAame"
attrib!te2/)iGe%$al!e = "SociosData1able"
382
t-2e/Attrib!tes/A%%(attrib!te2)
t-2e/?article = seI!ence
"et!rn t-2e
n% )!nction
n% Class

?artial ?!blic Class Socios"oJ
Inherits S-stem/Data/Data"oJ

?ri5ate tableSocios As SociosData1able

)rien% S!b AeJ(,-$al rb As S-stem/Data/Data"oJ,!il%er)
H-,ase/AeJ(rb)
He/tableSocios = C1-2e(He/1able,SociosData1able)
n% S!b

?!blic ?ro2ert- AI)() As String
;et
"et!rn C1-2e(He(He/tableSocios/AI)Col!mn),String)
n% ;et
Set
He(He/tableSocios/AI)Col!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- Aombre() As String
;et
1r-
"et!rn C1-2e(He(He/tableSocios/AombreCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
383
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e la
col!mna 4Aombre4 %e la tabla 4Socios4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableSocios/AombreCol!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- A2elli%o1() As String
;et
1r-
"et!rn C1-2e(He(He/tableSocios/A2elli%o1Col!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e la
col!mna 4A2elli%o14 %e la tabla 4Socios4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableSocios/A2elli%o1Col!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- A2elli%o2() As String
;et
1r-
"et!rn C1-2e(He(He/tableSocios/A2elli%o2Col!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e la
col!mna 4A2elli%o24 %e la tabla 4Socios4 es D,A!ll/", e)
n% 1r-
n% ;et
384
Set
He(He/tableSocios/A2elli%o2Col!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- 1ele8ono() As String
;et
1r-
"et!rn C1-2e(He(He/tableSocios/1ele8onoCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e la
col!mna 41ele8ono4 %e la tabla 4Socios4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableSocios/1ele8onoCol!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- mail() As String
;et
1r-
"et!rn C1-2e(He(He/tableSocios/mailCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e la
col!mna 4mail4 %e la tabla 4Socios4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableSocios/mailCol!mn) = 5al!e
n% Set
n% ?ro2ert-
385

?!blic ?ro2ert- Direccion() As String
;et
1r-
"et!rn C1-2e(He(He/tableSocios/DireccionCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e la
col!mna 4Direccion4 %e la tabla 4Socios4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableSocios/DireccionCol!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- Ci!%a%() As String
;et
1r-
"et!rn C1-2e(He(He/tableSocios/Ci!%a%Col!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e la
col!mna 4Ci!%a%4 %e la tabla 4Socios4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableSocios/Ci!%a%Col!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- ?ro5incia() As String
;et
1r-
386
"et!rn C1-2e(He(He/tableSocios/?ro5inciaCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e la
col!mna 4?ro5incia4 %e la tabla 4Socios4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableSocios/?ro5inciaCol!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- C?() As String
;et
1r-
"et!rn C1-2e(He(He/tableSocios/C?Col!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e la
col!mna 4C?4 %e la tabla 4Socios4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableSocios/C?Col!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic )!nction IsAombreA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableSocios/AombreCol!mn)
n% )!nction

?!blic S!b SetAombreA!ll()
He(He/tableSocios/AombreCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b
387

?!blic )!nction IsA2elli%o1A!ll() As ,oolean
"et!rn He/IsA!ll(He/tableSocios/A2elli%o1Col!mn)
n% )!nction

?!blic S!b SetA2elli%o1A!ll()
He(He/tableSocios/A2elli%o1Col!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsA2elli%o2A!ll() As ,oolean
"et!rn He/IsA!ll(He/tableSocios/A2elli%o2Col!mn)
n% )!nction

?!blic S!b SetA2elli%o2A!ll()
He(He/tableSocios/A2elli%o2Col!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction Is1ele8onoA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableSocios/1ele8onoCol!mn)
n% )!nction

?!blic S!b Set1ele8onoA!ll()
He(He/tableSocios/1ele8onoCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsmailA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableSocios/mailCol!mn)
n% )!nction

?!blic S!b SetmailA!ll()
388
He(He/tableSocios/mailCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsDireccionA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableSocios/DireccionCol!mn)
n% )!nction

?!blic S!b SetDireccionA!ll()
He(He/tableSocios/DireccionCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsCi!%a%A!ll() As ,oolean
"et!rn He/IsA!ll(He/tableSocios/Ci!%a%Col!mn)
n% )!nction

?!blic S!b SetCi!%a%A!ll()
He(He/tableSocios/Ci!%a%Col!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction Is?ro5inciaA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableSocios/?ro5inciaCol!mn)
n% )!nction

?!blic S!b Set?ro5inciaA!ll()
He(He/tableSocios/?ro5inciaCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsC?A!ll() As ,oolean
"et!rn He/IsA!ll(He/tableSocios/C?Col!mn)
n% )!nction
389

?!blic S!b SetC?A!ll()
He(He/tableSocios/C?Col!mn) = S-stem/Con5ert/D,A!ll
n% S!b
n% Class

?!blic Class Socios"oJChange5ent
Inherits S-stem/5entArgs

?ri5ate e5ent"oJ As Socios"oJ

?ri5ate e5entAction As S-stem/Data/Data"oJAction

?!blic S!b AeJ(,-$al roJ As Socios"oJ, ,-$al action As
S-stem/Data/Data"oJAction)
H-,ase/AeJ
He/e5ent"oJ = roJ
He/e5entAction = action
n% S!b

?!blic "ea%0nl- ?ro2ert- "oJ() As Socios"oJ
;et
"et!rn He/e5ent"oJ
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- Action() As S-stem/Data/Data"oJAction
;et
"et!rn He/e5entAction
n% ;et
n% ?ro2ert-
390
n% Class
n% Class
Aames2ace DataSet11ableA%a2ters

(S-stem/Com2onentHo%el/DesignerCategor-Attrib!te("co%e"), +
S-stem/Com2onentHo%el/1oolboGItem(tr!e), +
S-stem/Com2onentHo%el/Data0b#ectAttrib!te(tr!e), +

S-stem/Com2onentHo%el/DesignerAttrib!te("Hicroso8t/$SDesigner/DataSo!rce/De
sign/1ableA%a2terDesigner, Hicroso8t/$SDesigner"P +
", $ersion=X/0/0/0, C!lt!re=ne!tral,
?!blicZe-1oQen=b03858N811%50a3a"), +

S-stem/Com2onentHo%el/Design/Hel2Ze-Jor%Attrib!te("5s/%ata/1ableA%a2ter")*
+
?artial ?!blic Class Socios1ableA%a2ter
Inherits S-stem/Com2onentHo%el/Com2onent

?ri5ate <ith5ents m+a%a2ter As S-stem/Data/SIlClient/SIlDataA%a2ter

?ri5ate m+connection As S-stem/Data/SIlClient/SIlConnection

?ri5ate m+comman%Collection() As S-stem/Data/SIlClient/SIlComman%

?ri5ate m+clear,e8ore)ill As ,oolean

?!blic S!b AeJ()
H-,ase/AeJ
He/m+clear,e8ore)ill = tr!e
n% S!b

?ri5ate "ea%0nl- ?ro2ert- A%a2ter() As
S-stem/Data/SIlClient/SIlDataA%a2ter
391
;et
I8 (He/m+a%a2ter Is Aothing) 1hen
He/InitA%a2ter
n% I8
"et!rn He/m+a%a2ter
n% ;et
n% ?ro2ert-

)rien% ?ro2ert- Connection() As S-stem/Data/SIlClient/SIlConnection
;et
I8 (He/m+connection Is Aothing) 1hen
He/InitConnection
n% I8
"et!rn He/m+connection
n% ;et
Set
He/m+connection = 5al!e
I8 (Aot (He/A%a2ter/InsertComman%) Is Aothing) 1hen
He/A%a2ter/InsertComman%/Connection = 5al!e
n% I8
I8 (Aot (He/A%a2ter/DeleteComman%) Is Aothing) 1hen
He/A%a2ter/DeleteComman%/Connection = 5al!e
n% I8
I8 (Aot (He/A%a2ter/F2%ateComman%) Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/Connection = 5al!e
n% I8
Dim i As Integer = 0
Do <hile (i ( He/Comman%Collection/'ength)
I8 (Aot (He/Comman%Collection(i)) Is Aothing) 1hen
392

C1-2e(He/Comman%Collection(i),S-stem/Data/SIlClient/SIlComman%)/Connection
= 5al!e
n% I8
i = (i B 1)
'oo2
n% Set
n% ?ro2ert-

?rotecte% "ea%0nl- ?ro2ert- Comman%Collection() As
S-stem/Data/SIlClient/SIlComman%()
;et
I8 (He/m+comman%Collection Is Aothing) 1hen
He/InitComman%Collection
n% I8
"et!rn He/m+comman%Collection
n% ;et
n% ?ro2ert-

?!blic ?ro2ert- Clear,e8ore)ill() As ,oolean
;et
"et!rn He/m+clear,e8ore)ill
n% ;et
Set
He/m+clear,e8ore)ill = 5al!e
n% Set
n% ?ro2ert-

?ri5ate S!b InitA%a2ter()
He/m+a%a2ter = AeJ S-stem/Data/SIlClient/SIlDataA%a2ter
Dim tableHa22ing As S-stem/Data/Common/Data1ableHa22ing = AeJ
S-stem/Data/Common/Data1ableHa22ing
393
tableHa22ing/So!rce1able = "1able"
tableHa22ing/DataSet1able = "Socios"
tableHa22ing/Col!mnHa22ings/A%%("AI)", "AI)")
tableHa22ing/Col!mnHa22ings/A%%("Aombre", "Aombre")
tableHa22ing/Col!mnHa22ings/A%%("A2elli%o1", "A2elli%o1")
tableHa22ing/Col!mnHa22ings/A%%("A2elli%o2", "A2elli%o2")
tableHa22ing/Col!mnHa22ings/A%%("1ele8ono", "1ele8ono")
tableHa22ing/Col!mnHa22ings/A%%("mail", "mail")
tableHa22ing/Col!mnHa22ings/A%%("Direccion", "Direccion")
tableHa22ing/Col!mnHa22ings/A%%("Ci!%a%", "Ci!%a%")
tableHa22ing/Col!mnHa22ings/A%%("?ro5incia", "?ro5incia")
tableHa22ing/Col!mnHa22ings/A%%("C?", "C?")
He/m+a%a2ter/1ableHa22ings/A%%(tableHa22ing)
He/m+a%a2ter/DeleteComman% = AeJ S-stem/Data/SIlClient/SIlComman%
He/m+a%a2ter/DeleteComman%/Connection = He/Connection
He/m+a%a2ter/DeleteComman%/Comman%1eGt = "D'1 )"0H 9%bo:/
9Socios: <H" ((9AI): = \0riginal+AI)) AAD ((\IsA!ll+Aombre = "P +
"1 AAD 9Aombre: IS AF'') 0" (9Aombre: = \0riginal+Aombre)) AAD
((\IsA!ll+A2elli%o"P +
"1 = 1 AAD 9A2elli%o1: IS AF'') 0" (9A2elli%o1: =
\0riginal+A2elli%o1)) AAD ((\Is"P +
"A!ll+A2elli%o2 = 1 AAD 9A2elli%o2: IS AF'') 0" (9A2elli%o2: =
\0riginal+A2elli%o"P +
"2)) AAD ((\IsA!ll+1ele8ono = 1 AAD 91ele8ono: IS AF'') 0"
(91ele8ono: = \0rigina"P +
"l+1ele8ono)) AAD ((\IsA!ll+mail = 1 AAD 9mail: IS AF'') 0"
(9mail: = \0rigina"P +
"l+mail)) AAD ((\IsA!ll+Direccion = 1 AAD 9Direccion: IS AF'')
0" (9Direccion: ="P +
" \0riginal+Direccion)) AAD ((\IsA!ll+Ci!%a% = 1 AAD 9Ci!%a%:
IS AF'') 0" (9Ci!%a"P +
"%: = \0riginal+Ci!%a%)) AAD ((\IsA!ll+?ro5incia = 1 AAD
9?ro5incia: IS AF'') 0" "P +
"(9?ro5incia: = \0riginal+?ro5incia)) AAD ((\IsA!ll+C? = 1 AAD
9C?: IS AF'') 0" ("P +
"9C?: = \0riginal+C?)))"
394
He/m+a%a2ter/DeleteComman%/Comman%1-2e =
S-stem/Data/Comman%1-2e/1eGt
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+AI)",
S-stem/Data/SIlDb1-2e/AChar, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"AI)", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "", ""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+Aombre",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"Aombre", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "", ""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+Aombre",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Aombre", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+A2elli%o1",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"A2elli%o1", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+A2elli%o1",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "A2elli%o1", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "",
"", ""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+A2elli%o2",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"A2elli%o2", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+A2elli%o2",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "A2elli%o2", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "",
"", ""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+1ele8ono",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"1ele8ono", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+1ele8ono",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "1ele8ono", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+mail",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"mail", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "", ""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+mail",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "mail", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "",
""))
395
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+Direccion",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"Direccion", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+Direccion",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Direccion", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "",
"", ""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+Ci!%a%",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"Ci!%a%", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "", ""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+Ci!%a%",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Ci!%a%", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+?ro5incia",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"?ro5incia", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+?ro5incia",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "?ro5incia", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "",
"", ""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+C?", S-stem/Data/SIlDb1-2e/Int,
0, S-stem/Data/?arameterDirection/In2!t, 0, 0, "C?",
S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "", ""))
He/m+a%a2ter/DeleteComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+C?",
S-stem/Data/SIlDb1-2e/AChar, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"C?", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "", ""))
He/m+a%a2ter/InsertComman% = AeJ S-stem/Data/SIlClient/SIlComman%
He/m+a%a2ter/InsertComman%/Connection = He/Connection
He/m+a%a2ter/InsertComman%/Comman%1eGt = "IAS"1 IA10 9%bo:/
9Socios: (9AI):, 9Aombre:, 9A2elli%o1:, 9A2elli%o2:, 91ele8ono:"P +
", 9mail:, 9Direccion:, 9Ci!%a%:, 9?ro5incia:, 9C?:) $A'FS
(\AI), \Aombre, \A2e"P +
"lli%o1, \A2elli%o2, \1ele8ono, \mail, \Direccion, \Ci!%a%,
\?ro5incia,
\C?)["P;lobal/Hicroso8t/$is!al,asic/Chr<(13)P;lobal/Hicroso8t/$is!al,asic/C
hr<(10)P"S"P +
"'C1 AI), Aombre, A2elli%o1, A2elli%o2, 1ele8ono, mail,
Direccion, Ci!%a%, ?ro"P +
"5incia, C? )"0H Socios <H" (AI) = \AI))"
396
He/m+a%a2ter/InsertComman%/Comman%1-2e =
S-stem/Data/Comman%1-2e/1eGt
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\AI)", S-stem/Data/SIlDb1-2e/AChar, 0,
S-stem/Data/?arameterDirection/In2!t, 0, 0, "AI)",
S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "", ""))
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\Aombre",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Aombre", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\A2elli%o1",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "A2elli%o1", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\A2elli%o2",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "A2elli%o2", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\1ele8ono",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "1ele8ono", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\mail",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "mail", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\Direccion",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Direccion", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\Ci!%a%",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Ci!%a%", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\?ro5incia",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "?ro5incia", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/InsertComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\C?", S-stem/Data/SIlDb1-2e/AChar, 0,
S-stem/Data/?arameterDirection/In2!t, 0, 0, "C?",
S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "", ""))
He/m+a%a2ter/F2%ateComman% = AeJ S-stem/Data/SIlClient/SIlComman%
He/m+a%a2ter/F2%ateComman%/Connection = He/Connection
397
He/m+a%a2ter/F2%ateComman%/Comman%1eGt = "F?DA1 9%bo:/9Socios:
S1 9AI): = \AI), 9Aombre: = \Aombre, 9A2elli%o1: = \A2elli"P +
"%o1, 9A2elli%o2: = \A2elli%o2, 91ele8ono: = \1ele8ono, 9mail:
= \mail, 9Direcc"P +
"ion: = \Direccion, 9Ci!%a%: = \Ci!%a%, 9?ro5incia: =
\?ro5incia, 9C?: = \C? <H""P +
" ((9AI): = \0riginal+AI)) AAD ((\IsA!ll+Aombre = 1 AAD
9Aombre: IS AF'') 0" (9A"P +
"ombre: = \0riginal+Aombre)) AAD ((\IsA!ll+A2elli%o1 = 1 AAD
9A2elli%o1: IS AF'')"P +
" 0" (9A2elli%o1: = \0riginal+A2elli%o1)) AAD
((\IsA!ll+A2elli%o2 = 1 AAD 9A2elli"P +
"%o2: IS AF'') 0" (9A2elli%o2: = \0riginal+A2elli%o2)) AAD
((\IsA!ll+1ele8ono = 1"P +
" AAD 91ele8ono: IS AF'') 0" (91ele8ono: = \0riginal+1ele8ono))
AAD ((\IsA!ll+ma"P +
"il = 1 AAD 9mail: IS AF'') 0" (9mail: = \0riginal+mail))
AAD ((\IsA!ll+Direcc"P +
"ion = 1 AAD 9Direccion: IS AF'') 0" (9Direccion: =
\0riginal+Direccion)) AAD ((\"P +
"IsA!ll+Ci!%a% = 1 AAD 9Ci!%a%: IS AF'') 0" (9Ci!%a%: =
\0riginal+Ci!%a%)) AAD (("P +
"\IsA!ll+?ro5incia = 1 AAD 9?ro5incia: IS AF'') 0" (9?ro5incia:
= \0riginal+?ro5i"P +
"ncia)) AAD ((\IsA!ll+C? = 1 AAD 9C?: IS AF'') 0" (9C?: =
\0riginal+C?)))["P;lobal/Hicroso8t/$is!al,asic/Chr<(13)P;lobal/Hicroso8t/$i
s!al,asic/Chr<(10)P"S'C"P +
"1 AI), Aombre, A2elli%o1, A2elli%o2, 1ele8ono, mail,
Direccion, Ci!%a%, ?ro5inc"P +
"ia, C? )"0H Socios <H" (AI) = \AI))"
He/m+a%a2ter/F2%ateComman%/Comman%1-2e =
S-stem/Data/Comman%1-2e/1eGt
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\AI)", S-stem/Data/SIlDb1-2e/AChar, 0,
S-stem/Data/?arameterDirection/In2!t, 0, 0, "AI)",
S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\Aombre",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Aombre", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\A2elli%o1",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "A2elli%o1", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
398
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\A2elli%o2",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "A2elli%o2", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\1ele8ono",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "1ele8ono", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\mail",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "mail", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\Direccion",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Direccion", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\Ci!%a%",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Ci!%a%", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\?ro5incia",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "?ro5incia", S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\C?", S-stem/Data/SIlDb1-2e/AChar, 0,
S-stem/Data/?arameterDirection/In2!t, 0, 0, "C?",
S-stem/Data/Data"oJ$ersion/C!rrent, 8alse, Aothing, "", "", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+AI)",
S-stem/Data/SIlDb1-2e/AChar, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"AI)", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+Aombre",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"Aombre", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+Aombre",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Aombre", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+A2elli%o1",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"A2elli%o1", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+A2elli%o1",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
399
0, "A2elli%o1", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "",
"", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+A2elli%o2",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"A2elli%o2", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+A2elli%o2",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "A2elli%o2", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "",
"", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+1ele8ono",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"1ele8ono", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+1ele8ono",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "1ele8ono", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+mail",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"mail", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+mail",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "mail", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+Direccion",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"Direccion", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+Direccion",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Direccion", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "",
"", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+Ci!%a%",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"Ci!%a%", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+Ci!%a%",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "Ci!%a%", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "",
""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+?ro5incia",
S-stem/Data/SIlDb1-2e/Int, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"?ro5incia", S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "",
""))
400
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+?ro5incia",
S-stem/Data/SIlDb1-2e/A$arChar, 0, S-stem/Data/?arameterDirection/In2!t, 0,
0, "?ro5incia", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "",
"", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\IsA!ll+C?", S-stem/Data/SIlDb1-2e/Int,
0, S-stem/Data/?arameterDirection/In2!t, 0, 0, "C?",
S-stem/Data/Data"oJ$ersion/0riginal, tr!e, Aothing, "", "", ""))
He/m+a%a2ter/F2%ateComman%/?arameters/A%%(AeJ
S-stem/Data/SIlClient/SIl?arameter("\0riginal+C?",
S-stem/Data/SIlDb1-2e/AChar, 0, S-stem/Data/?arameterDirection/In2!t, 0, 0,
"C?", S-stem/Data/Data"oJ$ersion/0riginal, 8alse, Aothing, "", "", ""))
n% S!b

?ri5ate S!b InitConnection()
He/m+connection = AeJ S-stem/Data/SIlClient/SIlConnection
He/m+connection/ConnectionString =
<in%oJsA22lication3/Settings/De8a!lt/HSDA$i%eoConnectionString1
n% S!b

?ri5ate S!b InitComman%Collection()
He/m+comman%Collection = AeJ S-stem/Data/SIlClient/SIlComman%(0)
=>
He/m+comman%Collection(0) = AeJ S-stem/Data/SIlClient/SIlComman%
He/m+comman%Collection(0)/Connection = He/Connection
He/m+comman%Collection(0)/Comman%1eGt = "S'C1 AI), Aombre,
A2elli%o1, A2elli%o2, 1ele8ono, mail, Direccion, Ci!%a%, ?ro"P +
"5incia, C? )"0H %bo/Socios"
He/m+comman%Collection(0)/Comman%1-2e =
S-stem/Data/Comman%1-2e/1eGt
n% S!b


(S-stem/Com2onentHo%el/Data0b#ectHetho%Attrib!te(S-stem/Com2onentHo%el/Data
0b#ectHetho%1-2e/)ill, tr!e)* +
?!blic 05erloa%s 05erri%able )!nction )ill(,-$al %ata1able As
DataSet1/SociosData1able) As Integer
He/A%a2ter/SelectComman% = He/Comman%Collection(0)
I8 (He/m+clear,e8ore)ill = tr!e) 1hen
401
%ata1able/Clear
n% I8
Dim ret!rn$al!e As Integer = He/A%a2ter/)ill(%ata1able)
"et!rn ret!rn$al!e
n% )!nction


(S-stem/Com2onentHo%el/Data0b#ectHetho%Attrib!te(S-stem/Com2onentHo%el/Data
0b#ectHetho%1-2e/9Select:, tr!e)* +
?!blic 05erloa%s 05erri%able )!nction ;etData() As
DataSet1/SociosData1able
He/A%a2ter/SelectComman% = He/Comman%Collection(0)
Dim %ata1able As DataSet1/SociosData1able = AeJ
DataSet1/SociosData1able
He/A%a2ter/)ill(%ata1able)
"et!rn %ata1able
n% )!nction

?!blic 05erloa%s 05erri%able )!nction F2%ate(,-$al %ata1able As
DataSet1/SociosData1able) As Integer
"et!rn He/A%a2ter/F2%ate(%ata1able)
n% )!nction

?!blic 05erloa%s 05erri%able )!nction F2%ate(,-$al %ataSet As
DataSet1) As Integer
"et!rn He/A%a2ter/F2%ate(%ataSet, "Socios")
n% )!nction

?!blic 05erloa%s 05erri%able )!nction F2%ate(,-$al %ata"oJ As
S-stem/Data/Data"oJ) As Integer
"et!rn He/A%a2ter/F2%ate(AeJ S-stem/Data/Data"oJ() =%ata"oJ>)
n% )!nction

?!blic 05erloa%s 05erri%able )!nction F2%ate(,-$al %ata"oJs() As
S-stem/Data/Data"oJ) As Integer
402
"et!rn He/A%a2ter/F2%ate(%ata"oJs)
n% )!nction


(S-stem/Com2onentHo%el/Data0b#ectHetho%Attrib!te(S-stem/Com2onentHo%el/Data
0b#ectHetho%1-2e/Delete, tr!e)* +
?!blic 05erloa%s 05erri%able )!nction Delete(,-$al 0riginal+AI) As
String, ,-$al 0riginal+Aombre As String, ,-$al 0riginal+A2elli%o1 As
String, ,-$al 0riginal+A2elli%o2 As String, ,-$al 0riginal+1ele8ono As
String, ,-$al 0riginal+mail As String, ,-$al 0riginal+Direccion As String,
,-$al 0riginal+Ci!%a% As String, ,-$al 0riginal+?ro5incia As String, ,-$al
0riginal+C? As String) As Integer
I8 (0riginal+AI) Is Aothing) 1hen
1hroJ AeJ S-stem/Arg!mentA!llGce2tion("0riginal+AI)")
lse
He/A%a2ter/DeleteComman%/?arameters(0)/$al!e =
C1-2e(0riginal+AI),String)
n% I8
I8 (0riginal+Aombre Is Aothing) 1hen
He/A%a2ter/DeleteComman%/?arameters(1)/$al!e = C1-2e(1,Integer)
He/A%a2ter/DeleteComman%/?arameters(2)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/DeleteComman%/?arameters(1)/$al!e = C1-2e(0,Integer)
He/A%a2ter/DeleteComman%/?arameters(2)/$al!e =
C1-2e(0riginal+Aombre,String)
n% I8
I8 (0riginal+A2elli%o1 Is Aothing) 1hen
He/A%a2ter/DeleteComman%/?arameters(3)/$al!e = C1-2e(1,Integer)
He/A%a2ter/DeleteComman%/?arameters(.)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/DeleteComman%/?arameters(3)/$al!e = C1-2e(0,Integer)
He/A%a2ter/DeleteComman%/?arameters(.)/$al!e =
C1-2e(0riginal+A2elli%o1,String)
n% I8
I8 (0riginal+A2elli%o2 Is Aothing) 1hen
403
He/A%a2ter/DeleteComman%/?arameters(5)/$al!e = C1-2e(1,Integer)
He/A%a2ter/DeleteComman%/?arameters(6)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/DeleteComman%/?arameters(5)/$al!e = C1-2e(0,Integer)
He/A%a2ter/DeleteComman%/?arameters(6)/$al!e =
C1-2e(0riginal+A2elli%o2,String)
n% I8
I8 (0riginal+1ele8ono Is Aothing) 1hen
He/A%a2ter/DeleteComman%/?arameters(N)/$al!e = C1-2e(1,Integer)
He/A%a2ter/DeleteComman%/?arameters(X)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/DeleteComman%/?arameters(N)/$al!e = C1-2e(0,Integer)
He/A%a2ter/DeleteComman%/?arameters(X)/$al!e =
C1-2e(0riginal+1ele8ono,String)
n% I8
I8 (0riginal+mail Is Aothing) 1hen
He/A%a2ter/DeleteComman%/?arameters(E)/$al!e = C1-2e(1,Integer)
He/A%a2ter/DeleteComman%/?arameters(10)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/DeleteComman%/?arameters(E)/$al!e = C1-2e(0,Integer)
He/A%a2ter/DeleteComman%/?arameters(10)/$al!e =
C1-2e(0riginal+mail,String)
n% I8
I8 (0riginal+Direccion Is Aothing) 1hen
He/A%a2ter/DeleteComman%/?arameters(11)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/DeleteComman%/?arameters(12)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/DeleteComman%/?arameters(11)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/DeleteComman%/?arameters(12)/$al!e =
C1-2e(0riginal+Direccion,String)
404
n% I8
I8 (0riginal+Ci!%a% Is Aothing) 1hen
He/A%a2ter/DeleteComman%/?arameters(13)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/DeleteComman%/?arameters(1.)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/DeleteComman%/?arameters(13)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/DeleteComman%/?arameters(1.)/$al!e =
C1-2e(0riginal+Ci!%a%,String)
n% I8
I8 (0riginal+?ro5incia Is Aothing) 1hen
He/A%a2ter/DeleteComman%/?arameters(15)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/DeleteComman%/?arameters(16)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/DeleteComman%/?arameters(15)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/DeleteComman%/?arameters(16)/$al!e =
C1-2e(0riginal+?ro5incia,String)
n% I8
I8 (0riginal+C? Is Aothing) 1hen
He/A%a2ter/DeleteComman%/?arameters(1N)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/DeleteComman%/?arameters(1X)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/DeleteComman%/?arameters(1N)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/DeleteComman%/?arameters(1X)/$al!e =
C1-2e(0riginal+C?,String)
n% I8
Dim 2re5io!sConnectionState As S-stem/Data/ConnectionState =
He/A%a2ter/DeleteComman%/Connection/State
He/A%a2ter/DeleteComman%/Connection/02en
1r-
405
"et!rn He/A%a2ter/DeleteComman%/Gec!teAon]!er-
)inall-
I8 (2re5io!sConnectionState =
S-stem/Data/ConnectionState/Close%) 1hen
He/A%a2ter/DeleteComman%/Connection/Close
n% I8
n% 1r-
n% )!nction


(S-stem/Com2onentHo%el/Data0b#ectHetho%Attrib!te(S-stem/Com2onentHo%el/Data
0b#ectHetho%1-2e/Insert, tr!e)* +
?!blic 05erloa%s 05erri%able )!nction Insert(,-$al AI) As String,
,-$al Aombre As String, ,-$al A2elli%o1 As String, ,-$al A2elli%o2 As
String, ,-$al 1ele8ono As String, ,-$al mail As String, ,-$al Direccion As
String, ,-$al Ci!%a% As String, ,-$al ?ro5incia As String, ,-$al C? As
String) As Integer
I8 (AI) Is Aothing) 1hen
1hroJ AeJ S-stem/Arg!mentA!llGce2tion("AI)")
lse
He/A%a2ter/InsertComman%/?arameters(0)/$al!e =
C1-2e(AI),String)
n% I8
I8 (Aombre Is Aothing) 1hen
He/A%a2ter/InsertComman%/?arameters(1)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/InsertComman%/?arameters(1)/$al!e =
C1-2e(Aombre,String)
n% I8
I8 (A2elli%o1 Is Aothing) 1hen
He/A%a2ter/InsertComman%/?arameters(2)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/InsertComman%/?arameters(2)/$al!e =
C1-2e(A2elli%o1,String)
n% I8
406
I8 (A2elli%o2 Is Aothing) 1hen
He/A%a2ter/InsertComman%/?arameters(3)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/InsertComman%/?arameters(3)/$al!e =
C1-2e(A2elli%o2,String)
n% I8
I8 (1ele8ono Is Aothing) 1hen
He/A%a2ter/InsertComman%/?arameters(.)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/InsertComman%/?arameters(.)/$al!e =
C1-2e(1ele8ono,String)
n% I8
I8 (mail Is Aothing) 1hen
He/A%a2ter/InsertComman%/?arameters(5)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/InsertComman%/?arameters(5)/$al!e =
C1-2e(mail,String)
n% I8
I8 (Direccion Is Aothing) 1hen
He/A%a2ter/InsertComman%/?arameters(6)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/InsertComman%/?arameters(6)/$al!e =
C1-2e(Direccion,String)
n% I8
I8 (Ci!%a% Is Aothing) 1hen
He/A%a2ter/InsertComman%/?arameters(N)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/InsertComman%/?arameters(N)/$al!e =
C1-2e(Ci!%a%,String)
n% I8
I8 (?ro5incia Is Aothing) 1hen
407
He/A%a2ter/InsertComman%/?arameters(X)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/InsertComman%/?arameters(X)/$al!e =
C1-2e(?ro5incia,String)
n% I8
I8 (C? Is Aothing) 1hen
He/A%a2ter/InsertComman%/?arameters(E)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/InsertComman%/?arameters(E)/$al!e = C1-2e(C?,String)
n% I8
Dim 2re5io!sConnectionState As S-stem/Data/ConnectionState =
He/A%a2ter/InsertComman%/Connection/State
He/A%a2ter/InsertComman%/Connection/02en
1r-
"et!rn He/A%a2ter/InsertComman%/Gec!teAon]!er-
)inall-
I8 (2re5io!sConnectionState =
S-stem/Data/ConnectionState/Close%) 1hen
He/A%a2ter/InsertComman%/Connection/Close
n% I8
n% 1r-
n% )!nction


(S-stem/Com2onentHo%el/Data0b#ectHetho%Attrib!te(S-stem/Com2onentHo%el/Data
0b#ectHetho%1-2e/F2%ate, tr!e)* +
?!blic 05erloa%s 05erri%able )!nction F2%ate( +
,-$al AI) As String, +
,-$al Aombre As String, +
,-$al A2elli%o1 As String, +
,-$al A2elli%o2 As String, +
,-$al 1ele8ono As String, +
408
,-$al mail As String, +
,-$al Direccion As String, +
,-$al Ci!%a% As String, +
,-$al ?ro5incia As String, +
,-$al C? As String, +
,-$al 0riginal+AI) As String, +
,-$al 0riginal+Aombre As String, +
,-$al 0riginal+A2elli%o1 As String, +
,-$al 0riginal+A2elli%o2 As String, +
,-$al 0riginal+1ele8ono As String, +
,-$al 0riginal+mail As String, +
,-$al 0riginal+Direccion As String, +
,-$al 0riginal+Ci!%a% As String, +
,-$al 0riginal+?ro5incia As String, +
,-$al 0riginal+C? As String) As Integer
I8 (AI) Is Aothing) 1hen
1hroJ AeJ S-stem/Arg!mentA!llGce2tion("AI)")
lse
He/A%a2ter/F2%ateComman%/?arameters(0)/$al!e =
C1-2e(AI),String)
n% I8
I8 (Aombre Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(1)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(1)/$al!e =
C1-2e(Aombre,String)
n% I8
I8 (A2elli%o1 Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(2)/$al!e =
S-stem/D,A!ll/$al!e
lse
409
He/A%a2ter/F2%ateComman%/?arameters(2)/$al!e =
C1-2e(A2elli%o1,String)
n% I8
I8 (A2elli%o2 Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(3)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(3)/$al!e =
C1-2e(A2elli%o2,String)
n% I8
I8 (1ele8ono Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(.)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(.)/$al!e =
C1-2e(1ele8ono,String)
n% I8
I8 (mail Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(5)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(5)/$al!e =
C1-2e(mail,String)
n% I8
I8 (Direccion Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(6)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(6)/$al!e =
C1-2e(Direccion,String)
n% I8
I8 (Ci!%a% Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(N)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(N)/$al!e =
C1-2e(Ci!%a%,String)
410
n% I8
I8 (?ro5incia Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(X)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(X)/$al!e =
C1-2e(?ro5incia,String)
n% I8
I8 (C? Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(E)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(E)/$al!e = C1-2e(C?,String)
n% I8
I8 (0riginal+AI) Is Aothing) 1hen
1hroJ AeJ S-stem/Arg!mentA!llGce2tion("0riginal+AI)")
lse
He/A%a2ter/F2%ateComman%/?arameters(10)/$al!e =
C1-2e(0riginal+AI),String)
n% I8
I8 (0riginal+Aombre Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(11)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/F2%ateComman%/?arameters(12)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(11)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/F2%ateComman%/?arameters(12)/$al!e =
C1-2e(0riginal+Aombre,String)
n% I8
I8 (0riginal+A2elli%o1 Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(13)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/F2%ateComman%/?arameters(1.)/$al!e =
S-stem/D,A!ll/$al!e
411
lse
He/A%a2ter/F2%ateComman%/?arameters(13)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/F2%ateComman%/?arameters(1.)/$al!e =
C1-2e(0riginal+A2elli%o1,String)
n% I8
I8 (0riginal+A2elli%o2 Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(15)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/F2%ateComman%/?arameters(16)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(15)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/F2%ateComman%/?arameters(16)/$al!e =
C1-2e(0riginal+A2elli%o2,String)
n% I8
I8 (0riginal+1ele8ono Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(1N)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/F2%ateComman%/?arameters(1X)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(1N)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/F2%ateComman%/?arameters(1X)/$al!e =
C1-2e(0riginal+1ele8ono,String)
n% I8
I8 (0riginal+mail Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(1E)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/F2%ateComman%/?arameters(20)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(1E)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/F2%ateComman%/?arameters(20)/$al!e =
C1-2e(0riginal+mail,String)
412
n% I8
I8 (0riginal+Direccion Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(21)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/F2%ateComman%/?arameters(22)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(21)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/F2%ateComman%/?arameters(22)/$al!e =
C1-2e(0riginal+Direccion,String)
n% I8
I8 (0riginal+Ci!%a% Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(23)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/F2%ateComman%/?arameters(2.)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(23)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/F2%ateComman%/?arameters(2.)/$al!e =
C1-2e(0riginal+Ci!%a%,String)
n% I8
I8 (0riginal+?ro5incia Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(25)/$al!e =
C1-2e(1,Integer)
He/A%a2ter/F2%ateComman%/?arameters(26)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(25)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/F2%ateComman%/?arameters(26)/$al!e =
C1-2e(0riginal+?ro5incia,String)
n% I8
I8 (0riginal+C? Is Aothing) 1hen
He/A%a2ter/F2%ateComman%/?arameters(2N)/$al!e =
C1-2e(1,Integer)
413
He/A%a2ter/F2%ateComman%/?arameters(2X)/$al!e =
S-stem/D,A!ll/$al!e
lse
He/A%a2ter/F2%ateComman%/?arameters(2N)/$al!e =
C1-2e(0,Integer)
He/A%a2ter/F2%ateComman%/?arameters(2X)/$al!e =
C1-2e(0riginal+C?,String)
n% I8
Dim 2re5io!sConnectionState As S-stem/Data/ConnectionState =
He/A%a2ter/F2%ateComman%/Connection/State
He/A%a2ter/F2%ateComman%/Connection/02en
1r-
"et!rn He/A%a2ter/F2%ateComman%/Gec!teAon]!er-
)inall-
I8 (2re5io!sConnectionState =
S-stem/Data/ConnectionState/Close%) 1hen
He/A%a2ter/F2%ateComman%/Connection/Close
n% I8
n% 1r-
n% )!nction
n% Class
n% Aames2ace
Ms adelante veremos como usarlo, pero antes veremos otra forma de crear nuestro
DataSet tipado.
Esta que hemos visto, es la forma ms sencilla y habitual de crearlo, pero existe otra
manera que es un procedimiento manual que a modo general, conviene que la
conozcamos.

414

%(dulo B ? Cap!tulo B
B. 5enerando un "ataSet tipado con la l!nea de comandos
Otra manera de generar nuestros propios DataSets tipados es mediante la lnea de
comandos de MS-DOS con el uso de la herramienta ;sd.e;e.
A continuacin veremos como realizar esta tarea con este comando.


:sando la #erramienta GS".e;e
XSD no es otra cosa que un fichero ejecutable, que encontraremos en el SDK de .NET
y que nos permitir crear nuestros DataSet tipados de manera rpida y sencilla.
Para llevar a cabo nuestra tarea, abra una ventana MS-DOS y sitese en el directorio
en el cul tenemos instalado nuestro entorno #isual Basic 2BBC %&press, como se
indica en la figura 1.
415
&entana de M!/D:! situada en el directorio de &isual #asic ,++- 5press
Figura 1
Una vez situados sobre este directorio, nos moveremos al subdirectorio
.D?@$2*0@in tal y como se indica en la figura 2.
&entana de M!/D:! situada en el subdirectorio #in de &isual #asic ,++- 5press
Figura 2
416
A continuacin, lo que deberemos hacer es el fichero &sd correspondiente.
Para eso, deberemos hacerlo mediante un editor de textos o bien, desde una pequea
aplicacin Windows que generaremos para tal propsito.
En nuestro caso lo haremos con una aplicacin Windows, para lo cul, iniciaremos un
nuevo proyecto de 4plicacin para Pindos.
En el formulario Windows, insertaremos un control Button tal y como se muestra en
la figura 3.
Control #utton insertado en el formulario de "eneracin del esquema
Figura 3
A continuacin, escribiremos el siguiente cdigo que lo que nos permitir, ser crear el
fichero o documento XML de extensin &sd correspondiente, el cul contiene la
informacin para generar el DataSet tipado.
El cdigo de la aplicacin de generacin del esquema es el que se detalla a
continuacin:
Im2orts S-stem/Data
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
417
4 stablecemos los 2ar6metros %e la coneGiSn
Dim HiSIlConnection As AeJ
SIlConnection("ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo")
4 In%icamos la sentencia S'C1 2ara la coneGiSn anterior
Dim HiSIlDataA%a2ter As AeJ SIlDataA%a2ter("S'C1 10? 1 O )"0H
S0CI0S", HiSIlConnection)
4 Declaramos !n ob#eto DataSet 2ara almacenar el conteni%o
Dim HiDataSet As AeJ DataSet()
4 "ellenamos el DataSet
HiSIlDataA%a2ter/)ill(HiDataSet, "S0CI0S")
4 Declaramos !n ob#eto Data1able
Dim HiData1able As Data1able = HiDataSet/1ables("S0CI0S")
4 Com2letamos alg!nos 2ar6metros %e los cam2os %e la tabla
HiData1able/Col!mns("AI)")/FniI!e = 1r!e
HiData1able/Col!mns("Aombre")/HaG'ength = 50
HiData1able/Col!mns("A2elli%o1")/HaG'ength = 50
HiData1able/Col!mns("A2elli%o2")/HaG'ength = 50
HiData1able/Col!mns("1ele8ono")/HaG'ength = 13
HiData1able/Col!mns("mail")/HaG'ength = 50
HiData1able/Col!mns("Direccion")/HaG'ength = 100
HiData1able/Col!mns("Ci!%a%")/HaG'ength = 50
HiData1able/Col!mns("?ro5incia")/HaG'ength = 50
HiData1able/Col!mns("C?")/HaG'ength = 50
4 scribimos el esI!ema %e la tabla al %isco %!ro %el ?C
HiDataSet/<riteLmlSchema("cDUHisI!ema/Gs%")
4 Cerramos la coneGiSn
HiSIlConnection/Close()
4 Hostramos !n mensa#e %e esI!ema crea%o correctamente
Hessage,oG/ShoJ("sI!ema crea%o correctamente")
n% S!b
n% Class
418
Una vez que hemos escrito el cdigo fuente necesario para generar el esquema,
ejecutaremos nuestra aplicacin, obteniendo una ejecucin afirmativa como la que se
indica en la figura 4.
jecucin del pro"rama de "eneracin del esquema
Figura 4
El cdigo de nuestro esquema, ser una vez que se ha creado, como se indica en el
siguiente cdigo:
(^Gml 5ersion="1/0" stan%alone="-es"^*
(GsDschema i%="AeJDataSet" Gmlns=""
GmlnsDGs="htt2D"VVJJJ/J3/orgV2001VLH'Schema" GmlnsDms%ata="!rnDschemasC
microso8tCcomDGmlCms%ata"*
(GsDelement name="AeJDataSet" ms%ataDIsDataSet="tr!e"
ms%ataDFseC!rrent'ocale="tr!e"*
(GsDcom2leG1-2e*
(GsDchoice min0cc!rs="0" maG0cc!rs="!nbo!n%e%"*
(GsDelement name="S0CI0S"*
(GsDcom2leG1-2e*
(GsDseI!ence*
(GsDelement name="AI)" t-2e="GsDstring" min0cc!rs="0" V*
(GsDelement name="Aombre" min0cc!rs="0"*
(GsDsim2le1-2e*
(GsDrestriction base="GsDstring"*
419
(GsDmaG'ength 5al!e="50" V*
(VGsDrestriction*
(VGsDsim2le1-2e*
(VGsDelement*
(GsDelement name="A2elli%o1" min0cc!rs="0"*
(GsDsim2le1-2e*
(GsDrestriction base="GsDstring"*
(GsDmaG'ength 5al!e="50" V*
(VGsDrestriction*
(VGsDsim2le1-2e*
(VGsDelement*
(GsDelement name="A2elli%o2" min0cc!rs="0"*
(GsDsim2le1-2e*
(GsDrestriction base="GsDstring"*
(GsDmaG'ength 5al!e="50" V*
(VGsDrestriction*
(VGsDsim2le1-2e*
(VGsDelement*
(GsDelement name="1ele8ono" min0cc!rs="0"*
(GsDsim2le1-2e*
(GsDrestriction base="GsDstring"*
(GsDmaG'ength 5al!e="13" V*
(VGsDrestriction*
(VGsDsim2le1-2e*
(VGsDelement*
(GsDelement name="mail" min0cc!rs="0"*
(GsDsim2le1-2e*
(GsDrestriction base="GsDstring"*
(GsDmaG'ength 5al!e="50" V*
(VGsDrestriction*
420
(VGsDsim2le1-2e*
(VGsDelement*
(GsDelement name="Direccion" min0cc!rs="0"*
(GsDsim2le1-2e*
(GsDrestriction base="GsDstring"*
(GsDmaG'ength 5al!e="100" V*
(VGsDrestriction*
(VGsDsim2le1-2e*
(VGsDelement*
(GsDelement name="Ci!%a%" min0cc!rs="0"*
(GsDsim2le1-2e*
(GsDrestriction base="GsDstring"*
(GsDmaG'ength 5al!e="50" V*
(VGsDrestriction*
(VGsDsim2le1-2e*
(VGsDelement*
(GsDelement name="?ro5incia" min0cc!rs="0"*
(GsDsim2le1-2e*
(GsDrestriction base="GsDstring"*
(GsDmaG'ength 5al!e="50" V*
(VGsDrestriction*
(VGsDsim2le1-2e*
(VGsDelement*
(GsDelement name="C?" min0cc!rs="0"*
(GsDsim2le1-2e*
(GsDrestriction base="GsDstring"*
(GsDmaG'ength 5al!e="50" V*
(VGsDrestriction*
(VGsDsim2le1-2e*
(VGsDelement*
421
(VGsDseI!ence*
(VGsDcom2leG1-2e*
(VGsDelement*
(VGsDchoice*
(VGsDcom2leG1-2e*
(GsD!niI!e name="Constraint1"*
(GsDselector G2ath="/"VVS0CI0S" V*
(GsD8iel% G2ath="AI)" V*
(VGsD!niI!e*
(VGsDelement*
(VGsDschema*
Lo que haremos a continuacin, ser utilizar la herramienta &sd*e&e que est dentro
del directorio .D?@$2*0@in.
Con la herramienta &sd*e&e, generaremos la clase que podremos usar para el
DataSet tipados.
Una vez por lo tanto, que estamos situados en la lnea de comandos de MS-DOS,
escribiremos la instruccin:
;sd c3TMiEs&uema.;sd 2d 2l3VB 2n3Mi/ataSet./ST%pedSocios 2o3c3T
Esto lo haremos tal y como se indica en la figura 5.
Comandos de creacin de la clase del esquema creado
Figura 5
422
Si todo ha ido correctamente, la clase para usar el DataSet tipado, se habr creado
como se indica en la figura 6.
Clase de Data!et tipado creada con la aplicacin 5sd*e5e
Figura 6
El cdigo de nuestra clase tendr un aspecto similar al que se indica en el siguiente
cdigo fuente:
4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCC
4 (a!toCgenerate%*
4 Fna herramienta generS este cS%igo/
4 $ersiSn %el motor en tiem2o %e e#ec!ciSnD2/0/50215/..
4
4 'os cambios en este archi5o 2o%rKan ca!sar !n com2ortamiento
incorrecto - se 2er%er6n si
4 el cS%igo se 5!el5e a generar/
4 (Va!toCgenerate%*
4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCC
02tion Strict 088
423
02tion G2licit 0n
Im2orts S-stem
4
4ste cS%igo 8!ente 8!e genera%o a!tom6ticamente 2or Gs%,
$ersiSn=2/0/50215/../
4
Aames2ace HiDataSet/DS1-2e%Socios

(Seriali&able(), +
S-stem/Com2onentHo%el/DesignerCategor-Attrib!te("co%e"), +
S-stem/Com2onentHo%el/1oolboGItem(tr!e), +

S-stem/Lml/Seriali&ation/LmlSchema?ro5i%erAttrib!te(";et1-2e%DataSetSchema"
), +
S-stem/Lml/Seriali&ation/Lml"ootAttrib!te("AeJDataSet"), +
S-stem/Com2onentHo%el/Design/Hel2Ze-Jor%Attrib!te("5s/%ata/DataSet"),
+

S-stem/Diagnostics/Co%eAnal-sis/S!22ressHessageAttrib!te("Hicroso8t/Fsage",
"CA22.0DIm2lementISeriali&ableCorrectl-")* +
?artial ?!blic Class AeJDataSet
Inherits S-stem/Data/DataSet

?ri5ate tableS0CI0S As S0CI0SData1able

?ri5ate +schemaSeriali&ationHo%e As
S-stem/Data/SchemaSeriali&ationHo%e =
S-stem/Data/SchemaSeriali&ationHo%e/Incl!%eSchema


(S-stem/Diagnostics/Co%eAnal-sis/S!22ressHessageAttrib!te("Hicroso8t/Fsage"
, "CA221.DDoAotCall05erri%ableHetho%sInConstr!ctors")* +
?!blic S!b AeJ()
H-,ase/AeJ
424
He/,eginInit
He/InitClass
Dim schemaChange%Han%ler As
S-stem/Com2onentHo%el/CollectionChange5entHan%ler = A%%ress08
He/SchemaChange%
A%%Han%ler H-,ase/1ables/CollectionChange%, schemaChange%Han%ler
A%%Han%ler H-,ase/"elations/CollectionChange%,
schemaChange%Han%ler
He/n%Init
n% S!b


(S-stem/Diagnostics/Co%eAnal-sis/S!22ressHessageAttrib!te("Hicroso8t/Fsage"
, "CA221.DDoAotCall05erri%ableHetho%sInConstr!ctors")* +
?rotecte% S!b AeJ(,-$al in8o As
S-stem/"!ntime/Seriali&ation/Seriali&ationIn8o, ,-$al conteGt As
S-stem/"!ntime/Seriali&ation/StreamingConteGt)
H-,ase/AeJ(in8o, conteGt)
I8 (He/Is,inar-Seriali&e%(in8o, conteGt) = tr!e) 1hen
He/Init$ars(8alse)
Dim schemaChange%Han%ler1 As
S-stem/Com2onentHo%el/CollectionChange5entHan%ler = A%%ress08
He/SchemaChange%
A%%Han%ler He/1ables/CollectionChange%, schemaChange%Han%ler1
A%%Han%ler He/"elations/CollectionChange%,
schemaChange%Han%ler1
"et!rn
n% I8
Dim strSchema As String = C1-2e(in8o/;et$al!e("LmlSchema",
;et1-2e(String)),String)
I8 (He/DetermineSchemaSeriali&ationHo%e(in8o, conteGt) =
S-stem/Data/SchemaSeriali&ationHo%e/Incl!%eSchema) 1hen
Dim %s As S-stem/Data/DataSet = AeJ S-stem/Data/DataSet
%s/"ea%LmlSchema(AeJ S-stem/Lml/Lml1eGt"ea%er(AeJ
S-stem/I0/String"ea%er(strSchema)))
I8 (Aot (%s/1ables("S0CI0S")) Is Aothing) 1hen
H-,ase/1ables/A%%(AeJ S0CI0SData1able(%s/1ables("S0CI0S")))
n% I8
425
He/DataSetAame = %s/DataSetAame
He/?re8iG = %s/?re8iG
He/Aames2ace = %s/Aames2ace
He/'ocale = %s/'ocale
He/CaseSensiti5e = %s/CaseSensiti5e
He/n8orceConstraints = %s/n8orceConstraints
He/Herge(%s, 8alse, S-stem/Data/HissingSchemaAction/A%%)
He/Init$ars
lse
He/"ea%LmlSchema(AeJ S-stem/Lml/Lml1eGt"ea%er(AeJ
S-stem/I0/String"ea%er(strSchema)))
n% I8
He/;etSeriali&ationData(in8o, conteGt)
Dim schemaChange%Han%ler As
S-stem/Com2onentHo%el/CollectionChange5entHan%ler = A%%ress08
He/SchemaChange%
A%%Han%ler H-,ase/1ables/CollectionChange%, schemaChange%Han%ler
A%%Han%ler He/"elations/CollectionChange%, schemaChange%Han%ler
n% S!b

(S-stem/Com2onentHo%el/,roJsable(8alse), +

S-stem/Com2onentHo%el/DesignerSeriali&ation$isibilit-(S-stem/Com2onentHo%el
/DesignerSeriali&ation$isibilit-/Content)* +
?!blic "ea%0nl- ?ro2ert- S0CI0S() As S0CI0SData1able
;et
"et!rn He/tableS0CI0S
n% ;et
n% ?ro2ert-

?!blic 05erri%es ?ro2ert- SchemaSeriali&ationHo%e() As
S-stem/Data/SchemaSeriali&ationHo%e
;et
"et!rn He/+schemaSeriali&ationHo%e
426
n% ;et
Set
He/+schemaSeriali&ationHo%e = 5al!e
n% Set
n% ?ro2ert-


(S-stem/Com2onentHo%el/DesignerSeriali&ation$isibilit-Attrib!te(S-stem/Com2
onentHo%el/DesignerSeriali&ation$isibilit-/Hi%%en)* +
?!blic Sha%oJs "ea%0nl- ?ro2ert- 1ables() As
S-stem/Data/Data1ableCollection
;et
"et!rn H-,ase/1ables
n% ;et
n% ?ro2ert-


(S-stem/Com2onentHo%el/DesignerSeriali&ation$isibilit-Attrib!te(S-stem/Com2
onentHo%el/DesignerSeriali&ation$isibilit-/Hi%%en)* +
?!blic Sha%oJs "ea%0nl- ?ro2ert- "elations() As
S-stem/Data/Data"elationCollection
;et
"et!rn H-,ase/"elations
n% ;et
n% ?ro2ert-

(S-stem/Com2onentHo%el/De8a!lt$al!eAttrib!te(tr!e)* +
?!blic Sha%oJs ?ro2ert- n8orceConstraints() As ,oolean
;et
"et!rn H-,ase/n8orceConstraints
n% ;et
Set
H-,ase/n8orceConstraints = 5al!e
n% Set
427
n% ?ro2ert-

?rotecte% 05erri%es S!b Initiali&eDeri5e%DataSet()
He/,eginInit
He/InitClass
He/n%Init
n% S!b

?!blic 05erri%es )!nction Clone() As S-stem/Data/DataSet
Dim cln As AeJDataSet = C1-2e(H-,ase/Clone,AeJDataSet)
cln/Init$ars
"et!rn cln
n% )!nction

?rotecte% 05erri%es )!nction Sho!l%Seriali&e1ables() As ,oolean
"et!rn 8alse
n% )!nction

?rotecte% 05erri%es )!nction Sho!l%Seriali&e"elations() As ,oolean
"et!rn 8alse
n% )!nction

?rotecte% 05erri%es S!b "ea%LmlSeriali&able(,-$al rea%er As
S-stem/Lml/Lml"ea%er)
I8 (He/DetermineSchemaSeriali&ationHo%e(rea%er) =
S-stem/Data/SchemaSeriali&ationHo%e/Incl!%eSchema) 1hen
He/"eset
Dim %s As S-stem/Data/DataSet = AeJ S-stem/Data/DataSet
%s/"ea%Lml(rea%er)
I8 (Aot (%s/1ables("S0CI0S")) Is Aothing) 1hen
H-,ase/1ables/A%%(AeJ S0CI0SData1able(%s/1ables("S0CI0S")))
n% I8
428
He/DataSetAame = %s/DataSetAame
He/?re8iG = %s/?re8iG
He/Aames2ace = %s/Aames2ace
He/'ocale = %s/'ocale
He/CaseSensiti5e = %s/CaseSensiti5e
He/n8orceConstraints = %s/n8orceConstraints
He/Herge(%s, 8alse, S-stem/Data/HissingSchemaAction/A%%)
He/Init$ars
lse
He/"ea%Lml(rea%er)
He/Init$ars
n% I8
n% S!b

?rotecte% 05erri%es )!nction ;etSchemaSeriali&able() As
S-stem/Lml/Schema/LmlSchema
Dim stream As S-stem/I0/Hemor-Stream = AeJ S-stem/I0/Hemor-Stream
He/<riteLmlSchema(AeJ S-stem/Lml/Lml1eGt<riter(stream, Aothing))
stream/?osition = 0
"et!rn S-stem/Lml/Schema/LmlSchema/"ea%(AeJ
S-stem/Lml/Lml1eGt"ea%er(stream), Aothing)
n% )!nction

)rien% 05erloa%s S!b Init$ars()
He/Init$ars(tr!e)
n% S!b

)rien% 05erloa%s S!b Init$ars(,-$al init1able As ,oolean)
He/tableS0CI0S = C1-2e(H-,ase/1ables("S0CI0S"),S0CI0SData1able)
I8 (init1able = tr!e) 1hen
I8 (Aot (He/tableS0CI0S) Is Aothing) 1hen
He/tableS0CI0S/Init$ars
429
n% I8
n% I8
n% S!b

?ri5ate S!b InitClass()
He/DataSetAame = "AeJDataSet"
He/?re8iG = ""
He/n8orceConstraints = tr!e
He/tableS0CI0S = AeJ S0CI0SData1able
H-,ase/1ables/A%%(He/tableS0CI0S)
n% S!b

?ri5ate )!nction Sho!l%Seriali&eS0CI0S() As ,oolean
"et!rn 8alse
n% )!nction

?ri5ate S!b SchemaChange%(,-$al sen%er As 0b#ect, ,-$al e As
S-stem/Com2onentHo%el/CollectionChange5entArgs)
I8 (e/Action =
S-stem/Com2onentHo%el/CollectionChangeAction/"emo5e) 1hen
He/Init$ars
n% I8
n% S!b

?!blic Share% )!nction ;et1-2e%DataSetSchema(,-$al Gs As
S-stem/Lml/Schema/LmlSchemaSet) As S-stem/Lml/Schema/LmlSchemaCom2leG1-2e
Dim %s As AeJDataSet = AeJ AeJDataSet
Dim t-2e As S-stem/Lml/Schema/LmlSchemaCom2leG1-2e = AeJ
S-stem/Lml/Schema/LmlSchemaCom2leG1-2e
Dim seI!ence As S-stem/Lml/Schema/LmlSchemaSeI!ence = AeJ
S-stem/Lml/Schema/LmlSchemaSeI!ence
Gs/A%%(%s/;etSchemaSeriali&able)
Dim an- As S-stem/Lml/Schema/LmlSchemaAn- = AeJ
S-stem/Lml/Schema/LmlSchemaAn-
430
an-/Aames2ace = %s/Aames2ace
seI!ence/Items/A%%(an-)
t-2e/?article = seI!ence
"et!rn t-2e
n% )!nction

?!blic Delegate S!b S0CI0S"oJChange5entHan%ler(,-$al sen%er As
0b#ect, ,-$al e As S0CI0S"oJChange5ent)

(S-stem/Seriali&able(), +

S-stem/Lml/Seriali&ation/LmlSchema?ro5i%erAttrib!te(";et1-2e%1ableSchema")*
+
?artial ?!blic Class S0CI0SData1able
Inherits S-stem/Data/Data1able
Im2lements S-stem/Collections/In!merable

?ri5ate col!mnAI) As S-stem/Data/DataCol!mn

?ri5ate col!mnAombre As S-stem/Data/DataCol!mn

?ri5ate col!mnA2elli%o1 As S-stem/Data/DataCol!mn

?ri5ate col!mnA2elli%o2 As S-stem/Data/DataCol!mn

?ri5ate col!mn1ele8ono As S-stem/Data/DataCol!mn

?ri5ate col!mnmail As S-stem/Data/DataCol!mn

?ri5ate col!mnDireccion As S-stem/Data/DataCol!mn

?ri5ate col!mnCi!%a% As S-stem/Data/DataCol!mn
431

?ri5ate col!mn?ro5incia As S-stem/Data/DataCol!mn

?ri5ate col!mnC? As S-stem/Data/DataCol!mn

?!blic S!b AeJ()
H-,ase/AeJ
He/1ableAame = "S0CI0S"
He/,eginInit
He/InitClass
He/n%Init
n% S!b

)rien% S!b AeJ(,-$al table As S-stem/Data/Data1able)
H-,ase/AeJ
He/1ableAame = table/1ableAame
I8 (table/CaseSensiti5e (* table/DataSet/CaseSensiti5e) 1hen
He/CaseSensiti5e = table/CaseSensiti5e
n% I8
I8 (table/'ocale/1oString (* table/DataSet/'ocale/1oString)
1hen
He/'ocale = table/'ocale
n% I8
I8 (table/Aames2ace (* table/DataSet/Aames2ace) 1hen
He/Aames2ace = table/Aames2ace
n% I8
He/?re8iG = table/?re8iG
He/Hinim!mCa2acit- = table/Hinim!mCa2acit-
n% S!b

432
?rotecte% S!b AeJ(,-$al in8o As
S-stem/"!ntime/Seriali&ation/Seriali&ationIn8o, ,-$al conteGt As
S-stem/"!ntime/Seriali&ation/StreamingConteGt)
H-,ase/AeJ(in8o, conteGt)
He/Init$ars
n% S!b

?!blic "ea%0nl- ?ro2ert- AI)Col!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnAI)
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- AombreCol!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnAombre
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- A2elli%o1Col!mn() As
S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnA2elli%o1
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- A2elli%o2Col!mn() As
S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnA2elli%o2
n% ;et
n% ?ro2ert-

433
?!blic "ea%0nl- ?ro2ert- 1ele8onoCol!mn() As
S-stem/Data/DataCol!mn
;et
"et!rn He/col!mn1ele8ono
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- mailCol!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnmail
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- DireccionCol!mn() As
S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnDireccion
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- Ci!%a%Col!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnCi!%a%
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- ?ro5inciaCol!mn() As
S-stem/Data/DataCol!mn
;et
"et!rn He/col!mn?ro5incia
n% ;et
n% ?ro2ert-
434

?!blic "ea%0nl- ?ro2ert- C?Col!mn() As S-stem/Data/DataCol!mn
;et
"et!rn He/col!mnC?
n% ;et
n% ?ro2ert-

(S-stem/Com2onentHo%el/,roJsable(8alse)* +
?!blic "ea%0nl- ?ro2ert- Co!nt() As Integer
;et
"et!rn He/"oJs/Co!nt
n% ;et
n% ?ro2ert-

?!blic De8a!lt "ea%0nl- ?ro2ert- Item(,-$al in%eG As Integer) As
S0CI0S"oJ
;et
"et!rn C1-2e(He/"oJs(in%eG),S0CI0S"oJ)
n% ;et
n% ?ro2ert-

?!blic 5ent S0CI0S"oJChange% As S0CI0S"oJChange5entHan%ler

?!blic 5ent S0CI0S"oJChanging As S0CI0S"oJChange5entHan%ler

?!blic 5ent S0CI0S"oJDelete% As S0CI0S"oJChange5entHan%ler

?!blic 5ent S0CI0S"oJDeleting As S0CI0S"oJChange5entHan%ler

?!blic 05erloa%s S!b A%%S0CI0S"oJ(,-$al roJ As S0CI0S"oJ)
He/"oJs/A%%(roJ)
435
n% S!b

?!blic 05erloa%s )!nction A%%S0CI0S"oJ(,-$al AI) As String, ,-$al
Aombre As String, ,-$al A2elli%o1 As String, ,-$al A2elli%o2 As String,
,-$al 1ele8ono As String, ,-$al mail As String, ,-$al Direccion As String,
,-$al Ci!%a% As String, ,-$al ?ro5incia As String, ,-$al C? As String) As
S0CI0S"oJ
Dim roJS0CI0S"oJ As S0CI0S"oJ = C1-2e(He/AeJ"oJ,S0CI0S"oJ)
roJS0CI0S"oJ/ItemArra- = AeJ 0b#ect() =AI), Aombre, A2elli%o1,
A2elli%o2, 1ele8ono, mail, Direccion, Ci!%a%, ?ro5incia, C?>
He/"oJs/A%%(roJS0CI0S"oJ)
"et!rn roJS0CI0S"oJ
n% )!nction

?!blic 05erri%able )!nction ;etn!merator() As
S-stem/Collections/In!merator Im2lements
S-stem/Collections/In!merable/;etn!merator
"et!rn He/"oJs/;etn!merator
n% )!nction

?!blic 05erri%es )!nction Clone() As S-stem/Data/Data1able
Dim cln As S0CI0SData1able =
C1-2e(H-,ase/Clone,S0CI0SData1able)
cln/Init$ars
"et!rn cln
n% )!nction

?rotecte% 05erri%es )!nction CreateInstance() As
S-stem/Data/Data1able
"et!rn AeJ S0CI0SData1able
n% )!nction

)rien% S!b Init$ars()
He/col!mnAI) = H-,ase/Col!mns("AI)")
He/col!mnAombre = H-,ase/Col!mns("Aombre")
He/col!mnA2elli%o1 = H-,ase/Col!mns("A2elli%o1")
436
He/col!mnA2elli%o2 = H-,ase/Col!mns("A2elli%o2")
He/col!mn1ele8ono = H-,ase/Col!mns("1ele8ono")
He/col!mnmail = H-,ase/Col!mns("mail")
He/col!mnDireccion = H-,ase/Col!mns("Direccion")
He/col!mnCi!%a% = H-,ase/Col!mns("Ci!%a%")
He/col!mn?ro5incia = H-,ase/Col!mns("?ro5incia")
He/col!mnC? = H-,ase/Col!mns("C?")
n% S!b

?ri5ate S!b InitClass()
He/col!mnAI) = AeJ S-stem/Data/DataCol!mn("AI)",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnAI))
He/col!mnAombre = AeJ S-stem/Data/DataCol!mn("Aombre",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnAombre)
He/col!mnA2elli%o1 = AeJ S-stem/Data/DataCol!mn("A2elli%o1",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnA2elli%o1)
He/col!mnA2elli%o2 = AeJ S-stem/Data/DataCol!mn("A2elli%o2",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnA2elli%o2)
He/col!mn1ele8ono = AeJ S-stem/Data/DataCol!mn("1ele8ono",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mn1ele8ono)
He/col!mnmail = AeJ S-stem/Data/DataCol!mn("mail",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnmail)
He/col!mnDireccion = AeJ S-stem/Data/DataCol!mn("Direccion",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnDireccion)
He/col!mnCi!%a% = AeJ S-stem/Data/DataCol!mn("Ci!%a%",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnCi!%a%)
He/col!mn?ro5incia = AeJ S-stem/Data/DataCol!mn("?ro5incia",
;et1-2e(String), Aothing, S-stem/Data/Ha22ing1-2e/lement)
437
H-,ase/Col!mns/A%%(He/col!mn?ro5incia)
He/col!mnC? = AeJ S-stem/Data/DataCol!mn("C?", ;et1-2e(String),
Aothing, S-stem/Data/Ha22ing1-2e/lement)
H-,ase/Col!mns/A%%(He/col!mnC?)
He/Constraints/A%%(AeJ
S-stem/Data/FniI!eConstraint("Constraint1", AeJ S-stem/Data/DataCol!mn()
=He/col!mnAI)>, 8alse))
He/col!mnAI)/FniI!e = tr!e
He/col!mnAombre/HaG'ength = 50
He/col!mnA2elli%o1/HaG'ength = 50
He/col!mnA2elli%o2/HaG'ength = 50
He/col!mn1ele8ono/HaG'ength = 13
He/col!mnmail/HaG'ength = 50
He/col!mnDireccion/HaG'ength = 100
He/col!mnCi!%a%/HaG'ength = 50
He/col!mn?ro5incia/HaG'ength = 50
He/col!mnC?/HaG'ength = 50
n% S!b

?!blic )!nction AeJS0CI0S"oJ() As S0CI0S"oJ
"et!rn C1-2e(He/AeJ"oJ,S0CI0S"oJ)
n% )!nction

?rotecte% 05erri%es )!nction AeJ"oJ)rom,!il%er(,-$al b!il%er As
S-stem/Data/Data"oJ,!il%er) As S-stem/Data/Data"oJ
"et!rn AeJ S0CI0S"oJ(b!il%er)
n% )!nction

?rotecte% 05erri%es )!nction ;et"oJ1-2e() As S-stem/1-2e
"et!rn ;et1-2e(S0CI0S"oJ)
n% )!nction

438
?rotecte% 05erri%es S!b 0n"oJChange%(,-$al e As
S-stem/Data/Data"oJChange5entArgs)
H-,ase/0n"oJChange%(e)
I8 (Aot (He/S0CI0S"oJChange%5ent) Is Aothing) 1hen
"aise5ent S0CI0S"oJChange%(He, AeJ
S0CI0S"oJChange5ent(C1-2e(e/"oJ,S0CI0S"oJ), e/Action))
n% I8
n% S!b

?rotecte% 05erri%es S!b 0n"oJChanging(,-$al e As
S-stem/Data/Data"oJChange5entArgs)
H-,ase/0n"oJChanging(e)
I8 (Aot (He/S0CI0S"oJChanging5ent) Is Aothing) 1hen
"aise5ent S0CI0S"oJChanging(He, AeJ
S0CI0S"oJChange5ent(C1-2e(e/"oJ,S0CI0S"oJ), e/Action))
n% I8
n% S!b

?rotecte% 05erri%es S!b 0n"oJDelete%(,-$al e As
S-stem/Data/Data"oJChange5entArgs)
H-,ase/0n"oJDelete%(e)
I8 (Aot (He/S0CI0S"oJDelete%5ent) Is Aothing) 1hen
"aise5ent S0CI0S"oJDelete%(He, AeJ
S0CI0S"oJChange5ent(C1-2e(e/"oJ,S0CI0S"oJ), e/Action))
n% I8
n% S!b

?rotecte% 05erri%es S!b 0n"oJDeleting(,-$al e As
S-stem/Data/Data"oJChange5entArgs)
H-,ase/0n"oJDeleting(e)
I8 (Aot (He/S0CI0S"oJDeleting5ent) Is Aothing) 1hen
"aise5ent S0CI0S"oJDeleting(He, AeJ
S0CI0S"oJChange5ent(C1-2e(e/"oJ,S0CI0S"oJ), e/Action))
n% I8
n% S!b
439

?!blic S!b "emo5eS0CI0S"oJ(,-$al roJ As S0CI0S"oJ)
He/"oJs/"emo5e(roJ)
n% S!b

?!blic Share% )!nction ;et1-2e%1ableSchema(,-$al Gs As
S-stem/Lml/Schema/LmlSchemaSet) As S-stem/Lml/Schema/LmlSchemaCom2leG1-2e
Dim t-2e As S-stem/Lml/Schema/LmlSchemaCom2leG1-2e = AeJ
S-stem/Lml/Schema/LmlSchemaCom2leG1-2e
Dim seI!ence As S-stem/Lml/Schema/LmlSchemaSeI!ence = AeJ
S-stem/Lml/Schema/LmlSchemaSeI!ence
Dim %s As AeJDataSet = AeJ AeJDataSet
Gs/A%%(%s/;etSchemaSeriali&able)
Dim an-1 As S-stem/Lml/Schema/LmlSchemaAn- = AeJ
S-stem/Lml/Schema/LmlSchemaAn-
an-1/Aames2ace = "htt2D"VVJJJ/J3/orgV2001VLH'Schema"
an-1/Hin0cc!rs = AeJ Decimal(0)
an-1/HaG0cc!rs = Decimal/HaG$al!e
an-1/?rocessContents =
S-stem/Lml/Schema/LmlSchemaContent?rocessing/'aG
seI!ence/Items/A%%(an-1)
Dim an-2 As S-stem/Lml/Schema/LmlSchemaAn- = AeJ
S-stem/Lml/Schema/LmlSchemaAn-
an-2/Aames2ace = "!rnDschemasCmicroso8tCcomDGmlC%i88gramC51"
an-2/Hin0cc!rs = AeJ Decimal(1)
an-2/?rocessContents =
S-stem/Lml/Schema/LmlSchemaContent?rocessing/'aG
seI!ence/Items/A%%(an-2)
Dim attrib!te1 As S-stem/Lml/Schema/LmlSchemaAttrib!te = AeJ
S-stem/Lml/Schema/LmlSchemaAttrib!te
attrib!te1/Aame = "names2ace"
attrib!te1/)iGe%$al!e = %s/Aames2ace
t-2e/Attrib!tes/A%%(attrib!te1)
Dim attrib!te2 As S-stem/Lml/Schema/LmlSchemaAttrib!te = AeJ
S-stem/Lml/Schema/LmlSchemaAttrib!te
attrib!te2/Aame = "table1-2eAame"
440
attrib!te2/)iGe%$al!e = "S0CI0SData1able"
t-2e/Attrib!tes/A%%(attrib!te2)
t-2e/?article = seI!ence
"et!rn t-2e
n% )!nction
n% Class

?artial ?!blic Class S0CI0S"oJ
Inherits S-stem/Data/Data"oJ

?ri5ate tableS0CI0S As S0CI0SData1able

)rien% S!b AeJ(,-$al rb As S-stem/Data/Data"oJ,!il%er)
H-,ase/AeJ(rb)
He/tableS0CI0S = C1-2e(He/1able,S0CI0SData1able)
n% S!b

?!blic ?ro2ert- AI)() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/AI)Col!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 4AI)4 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableS0CI0S/AI)Col!mn) = 5al!e
n% Set
n% ?ro2ert-

441
?!blic ?ro2ert- Aombre() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/AombreCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 4Aombre4 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableS0CI0S/AombreCol!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- A2elli%o1() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/A2elli%o1Col!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 4A2elli%o14 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableS0CI0S/A2elli%o1Col!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- A2elli%o2() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/A2elli%o2Col!mn),String)
442
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 4A2elli%o24 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableS0CI0S/A2elli%o2Col!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- 1ele8ono() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/1ele8onoCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 41ele8ono4 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableS0CI0S/1ele8onoCol!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- mail() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/mailCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 4mail4 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
443
n% ;et
Set
He(He/tableS0CI0S/mailCol!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- Direccion() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/DireccionCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 4Direccion4 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableS0CI0S/DireccionCol!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- Ci!%a%() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/Ci!%a%Col!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 4Ci!%a%4 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableS0CI0S/Ci!%a%Col!mn) = 5al!e
n% Set
444
n% ?ro2ert-

?!blic ?ro2ert- ?ro5incia() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/?ro5inciaCol!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 4?ro5incia4 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableS0CI0S/?ro5inciaCol!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic ?ro2ert- C?() As String
;et
1r-
"et!rn C1-2e(He(He/tableS0CI0S/C?Col!mn),String)
Catch e As S-stem/In5ali%CastGce2tion
1hroJ AeJ S-stem/Data/Strong1-2ingGce2tion("l 5alor %e
la col!mna 4C?4 %e la tabla 4S0CI0S4 es D,A!ll/", e)
n% 1r-
n% ;et
Set
He(He/tableS0CI0S/C?Col!mn) = 5al!e
n% Set
n% ?ro2ert-

?!blic )!nction IsAI)A!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/AI)Col!mn)
445
n% )!nction

?!blic S!b SetAI)A!ll()
He(He/tableS0CI0S/AI)Col!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsAombreA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/AombreCol!mn)
n% )!nction

?!blic S!b SetAombreA!ll()
He(He/tableS0CI0S/AombreCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsA2elli%o1A!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/A2elli%o1Col!mn)
n% )!nction

?!blic S!b SetA2elli%o1A!ll()
He(He/tableS0CI0S/A2elli%o1Col!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsA2elli%o2A!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/A2elli%o2Col!mn)
n% )!nction

?!blic S!b SetA2elli%o2A!ll()
He(He/tableS0CI0S/A2elli%o2Col!mn) = S-stem/Con5ert/D,A!ll
n% S!b

446
?!blic )!nction Is1ele8onoA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/1ele8onoCol!mn)
n% )!nction

?!blic S!b Set1ele8onoA!ll()
He(He/tableS0CI0S/1ele8onoCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsmailA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/mailCol!mn)
n% )!nction

?!blic S!b SetmailA!ll()
He(He/tableS0CI0S/mailCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsDireccionA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/DireccionCol!mn)
n% )!nction

?!blic S!b SetDireccionA!ll()
He(He/tableS0CI0S/DireccionCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsCi!%a%A!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/Ci!%a%Col!mn)
n% )!nction

?!blic S!b SetCi!%a%A!ll()
He(He/tableS0CI0S/Ci!%a%Col!mn) = S-stem/Con5ert/D,A!ll
447
n% S!b

?!blic )!nction Is?ro5inciaA!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/?ro5inciaCol!mn)
n% )!nction

?!blic S!b Set?ro5inciaA!ll()
He(He/tableS0CI0S/?ro5inciaCol!mn) = S-stem/Con5ert/D,A!ll
n% S!b

?!blic )!nction IsC?A!ll() As ,oolean
"et!rn He/IsA!ll(He/tableS0CI0S/C?Col!mn)
n% )!nction

?!blic S!b SetC?A!ll()
He(He/tableS0CI0S/C?Col!mn) = S-stem/Con5ert/D,A!ll
n% S!b
n% Class

?!blic Class S0CI0S"oJChange5ent
Inherits S-stem/5entArgs

?ri5ate e5ent"oJ As S0CI0S"oJ

?ri5ate e5entAction As S-stem/Data/Data"oJAction

?!blic S!b AeJ(,-$al roJ As S0CI0S"oJ, ,-$al action As
S-stem/Data/Data"oJAction)
H-,ase/AeJ
He/e5ent"oJ = roJ
He/e5entAction = action
448
n% S!b

?!blic "ea%0nl- ?ro2ert- "oJ() As S0CI0S"oJ
;et
"et!rn He/e5ent"oJ
n% ;et
n% ?ro2ert-

?!blic "ea%0nl- ?ro2ert- Action() As S-stem/Data/Data"oJAction
;et
"et!rn He/e5entAction
n% ;et
n% ?ro2ert-
n% Class
n% Class
n% Aames2ace
En este punto, podemos incluir el archivo (i%s9uema.b a nuestro proyecto, o bien
compilarlo desde la lnea de comandos o desde el entorno de desarrollo.
Sin embargo, no realizaremos esa accin. Tan slo comentar que si quisiramos
compilar desde la lnea de comandos el fichero con el compilador de Visual Basic,
utilizaramos el fichero ejecutable v#c.e;e, que corresponde con las iniciales de #isual
Basic compiler.
Ahora que ya sabemos como generar nuestros DataSet tipados, aprenderemos a
usarlos en nuestras aplicaciones.

449

%(dulo B ? Cap!tulo B
3. :sando los "ataSets tipados
A continuacin veremos un ejemplo del uso de DataSets tipados utilizando #isual
Basic 2BBC %&press.
Para esto nos servir lo que ya hemos visto en la generacin de un DataSet tipado con
#isual Basic 2BBC %&press.
Recordemos que ya habamos aadido un elemento DataSetH.&sd a nuestro proyecto,
tal y como se muestra en la figura 1.
450
Data!et.*5sd de ejemplo8 a2adido al formulario8 para utili4arlo como Data!et tipado
Figura 1


:so r&pido de nuestro "ataSet tipado
El uso de un DataSet tipado, no tiene muchas diferencias respecto a un DataSet no
tipado. Este ltimo ya lo hemos visto, y el DataSet tipado lo veremos a continuacin
de forma prctica.
Este primer ejemplo, muestra de forma sencilla, como trabajar con el esquema que
hemos creado y como hacerlo rpidamente a travs de nuestra aplicacin de prueba.
El cdigo de ejemplo que nos sirve de toma de contacto, es el que se indica a
continuacin:
Im2orts s-stem/%ata
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
451
4 stablecemos la coneGiSn
Dim HiSIlConnection As AeJ
SIlConnection("ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo")
4 Declaramos !n ob#eto DataA%a2ter - le in%icamos la coneGiSn
Dim HiSIlDataA%a2ter As AeJ SIlDataA%a2ter("S'C1 O )"0H S0CI0S",
HiSIlConnection)
4 Declaramos !n ob#eto DataSet con el esI!ema %el DataSet ti2a%o
Dim HiDt1-2e% As AeJ DataSet1
4 "ellenamos el DataSet ti2a%o con la in8ormaciSn %e la tabla %el
S'C1
HiSIlDataA%a2ter/)ill(HiDt1-2e%, "S0CI0S")
4 Declaramos !n ob#eto 2ara recorrer los %atos %el DataSet
Dim HisDatos As DataSet1/Socios"oJ
4 "ecorremos los %atos %el DataSet ti2a%o - los mostramos
)or ach HisDatos In HiDt1-2e%/Socios
Hessage,oG/ShoJ(HisDatos/Aombre P " " P HisDatos/A2elli%o1 P " " P
HisDatos/A2elli%o2)
AeGt
n% S!b
n% Class
Nuestro ejemplo en ejecucin, es el que se puede ver en la figura 2.
jemplo en ejecucin del uso sencillo de Data!ets tipados
Figura 2
452
A continuacin veremos otros tipos de ejecucin de DataSets tipados mucho ms
complejos.


Atenci(n especial al Cuadro de #erramientas
Cuando trabajamos con DataSets tipados como lo hemos hecho hasta ahora,
habremos notado que entre otras cosas, tenemos las capacidades o posibilidades de
trabajar con el DataSet como objetos.
Obviamente, estos objetos estn incluidos en el Cuadro de "erramientas, tal y como
puede verse en la figura 3.
Componentes creados por el entorno para trabajar con Data!ets tipados
Figura 3
Para trabajar con ellos, podemos arrastrarlos sobre el formulario como hacemos con
cualquier control o componente.


:sando las #erramientas autom&ticas para trabaar con "ataSets tipados
An as, vamos a arrastrar sobre el formulario, un componente DataSet como se indica
en la figura 4.
!eleccin de un control Data!et del Cuadro de %erramientas
Figura 4
453
En este punto, recordemos que tenemos nuestro DataSet tipado o esquema ya creado
y que para usar este esquema desde nuestro objeto DataSet, podemos utilizar las
herramientas del entorno .NET.
Cuando arrastramos el componente DataSet sobre el formulario, aparecer una
ventana como que se muestra en la figura 5, y que nos permitir indicar si se trata de
un DataSet tipado o un DataSet no tipado.
&entana para a"re"ar un conjunto de datos
Figura 5
Por defecto, aparecer seleccionada la opcin de Conjunto de datos con tipo y el
DataSet o esquema que hemos creado.
Pulsaremos el botn 4ceptar y de esta manera, nuestro objeto DataSet habr
quedado insertado y preparado en el formulario, para utilizar el esquema del DataSet
indicado.
Para no complicarlo, he decidido renombrar el control DataSet como dtSet.
El DataSet quedar insertado en nuestro entorno como se indica en la figura 6.
454
Control Data!et Cdt!etD insertado en el formulario de ejemplo
Figura 6
Para usar el objeto DataSet insertado, deberemos acceder a l a travs de cdigo, de
forma muy parecida a lo que lo hacamos anteriormente.
Im2orts s-stem/%ata
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
4 stablecemos la coneGiSn
Dim HiSIlConnection As AeJ
SIlConnection("ser5er=/[!i%=sa[2assJor%=$is!al,asic[%atabase=HSDA$i%eo")
4 Declaramos !n ob#eto DataA%a2ter - le in%icamos la coneGiSn
455
Dim HiSIlDataA%a2ter As AeJ SIlDataA%a2ter("S'C1 O )"0H S0CI0S",
HiSIlConnection)
4 "ellenamos el DataSet ti2a%o con la in8ormaciSn %e la tabla %el
S'C1
HiSIlDataA%a2ter/)ill(%tSet, "S0CI0S")
4 Declaramos !n ob#eto 2ara recorrer los %atos %el DataSet
Dim HisDatos As DataSet1/Socios"oJ
4 "ecorremos los %atos %el DataSet ti2a%o - los mostramos
)or ach HisDatos In %tSet/Socios
Hessage,oG/ShoJ(HisDatos/Aombre P " " P HisDatos/A2elli%o1 P " " P
HisDatos/A2elli%o2)
AeGt
n% S!b
n% Class
El funcionamiento de nuestra aplicacin de ejemplo, es igual al que hemos visto en la
figura 2.


:sando "ataAdapter con "ataSets tipados
Escribiremos a continuacin una pequea aplicacin Windows como la hemos hecho
anteriormente.
Crearemos nuestro esquema como lo hemos hecho hasta ahora y aadiremos dos
botones como se indica en la figura 7.DataSet como se indica en la figura 4.
456
#otones del ejemplo a2adidos a la ventana 6indo7s
Figura 7
A continuacin aadiremos un DataSet al cul le asignaremos el nombre del DataSet
tipado correspondiente al esquema creado, tal y como se indica en la figura 8.
Data!et tipado del esquema asi"nado al objeto Data!et
Figura 8
A este objeto DataSet, le he llamado dtSet.
A continuacin, aadiremos un componente S9lData*dapter al formulario Windows.
En este punto, aparecer una ventana como la que se muestra en la figura 9.
457
Asistente del !qlDataAdapter
Figura 9
Elegiremos la conexin adecuada y pulsaremos el botn Si'uiente.
A continuacin, el asistente nos mostrar una informacin como la que se indica en la
figura 10.
458
:pcin para ele"ir el tipo de comando a utili4ar
Figura 10
Elegiremos la primera de las opciones que es la que se indica en la figura 10, y
pulsaremos nuevamente el botn Si'uiente.
El asistente continuar presentndonos ventanas de informacin para configurar
nuestro componente S9lData*dapter.
Dentro de esta ventana y dentro de los datos que deseamos cargar, escribiremos la
instruccin SQL S%L%CT U )'O( SOCIOS como se indica en la figura 11.
459
:pcin de "eneracin de las instrucciones !HL
Figura 11
A continuacin, pulsaremos el botn Si'uiente.
De esta manera, el asistente terminar de crear las instrucciones necesarias para
trabajar con el componente S9lData*dapter.
Si todo ha ido correctamente, aparecer una ventana como la que se indica en la
figura 12.
460
3esultados de la confi"uracin del componente !qlDataAdapter
Figura 12
Para concluir, haremos clic sobre el botn Finali@ar.
Automticamente, en #isual Basic 2BBC %&press, aparecer aadido al formulario
Windows el componente S9lConnection, como vemos en la figura 13.
461
Componentes a2adidos al formulario 6indo7s
Figura 13
A continuacin, escribiremos el cdigo fuente de la aplicacin, que se encarga de
recoger los datos de la base de datos, insertarlos en un DataSet, para modificarlos y
actualizar las modificaciones en la base de datos.
El cdigo fuente de la aplicacin, quedar como se detalla a continuacin:
Im2orts s-stem/%ata
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
Dim HiSIlConnection As SIlConnection
Dim HiSIlDataA%a2ter As SIlDataA%a2ter
462
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 "ellenamos el DataSet ti2a%o con la in8ormaciSn %e la tabla %el
S'C1
SIlDataA%a2ter1/)ill(%tSet, "S0CI0S")
n% S!b
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
4 Declaramos !n ob#eto 2ara traba#ar con los %atos %el DataSet
Dim HisDatos As DataSet1/Socios"oJ
4 Almacenamos en Rl, la in8ormaciSn %el DataSet 2ara
4 el AI) = "111111"
HisDatos = %tSet/Socios/)in%,-AI)("111111")
4 Ho%i8icaremos el cam2o C?
HisDatos/C? = "2X022"
4 Deshabilitamos como me%i%a %e seg!ri%a% el botSn
,!tton1/nable% = )alse
n% S!b
?ri5ate S!b ,!tton2+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton2/ClicQ
I8 %tSet/HasChanges 1hen
4 l DataSet tiene cambios
4 Declaramos !n ob#eto DataSet
Dim %tSetHo%i8ica%o As DataSet
4 'e 2asamos los %atos mo%i8ica%os en el DataSet original
%tSetHo%i8ica%o = %tSet/;etChanges
4 Act!ali&amos el DataSet I!e ha cambia%o a tra5Rs %el DataA%a2ter
SIlDataA%a2ter1/F2%ate(%tSetHo%i8ica%o)
4 Ace2tamos los cambios en el DataSet 2ara
4 seg!ir traba#an%o con Rl 2or e#em2lo
%tSet/Acce2tChanges()
463
4 Hostramos !n mensa#e en 2antalla in%ican%o I!e
4 se han mo%i8ica%o los %atos
Hessage,oG/ShoJ("'os cambios %el DataSet han si%o" P $bCr'8 P
"act!ali&a%os en la base %e %atos")
4 Deshabilitamos como me%i%a %e seg!ri%a% el botSn
,!tton2/nable% = )alse
lse
4 l DataSet no tiene cambios
Hessage,oG/ShoJ("Ao ha- cambios en el DataSet")
n% I8
n% S!b
n% Class
Nuestro ejemplo en ejecucin, es el que puede verse en la figura 14.
jemplo del DataAdapter y Data!et tipado en ejecucin
Figura 14
Nota3
Cuando trabajamos con un componente Data*dapter, aparece un
asistente. En el caso de elegir la opcin de generacin de sentencias
SELECT, UPDATE, DELETE e INSERT, el asistente crear a partir de la
SELECT, esas instrucciones por nosotros.
464
Dentro de este mismo ejemplo, aada otros dos botones como se muestra en la figura
15.
jemplo del DataAdapter y Data!et tipado en ejecucin
Figura 15
Estos botones nos servirn para aadir una fila nueva a nuestra base de datos y para
eliminar una fila existente (en nuestro caso la nueva fila aadida).
El cdigo fuente de nuestra aplicacin de ejemplo, es el que se detalla a continuacin:
Im2orts s-stem/%ata
Im2orts S-stem/Data/SIlClient
Im2orts S-stem/Lml
?!blic Class )orm1
Dim HiSIlConnection As SIlConnection
Dim HiSIlDataA%a2ter As SIlDataA%a2ter
465
?ri5ate S!b )orm1+'oa%(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les H-,ase/'oa%
4 Deshabilitamos el botSn %e ,orrar registro,
4 2orI!e hasta I!e no se cree no lo borraremos
,!tton./nable% = )alse
4 "ellenamos el DataSet ti2a%o con la in8ormaciSn %e la tabla %el
S'C1
SIlDataA%a2ter1/)ill(%tSet, "S0CI0S")
n% S!b
?ri5ate S!b ,!tton1+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton1/ClicQ
4 Declaramos !n ob#eto 2ara traba#ar con los %atos %el DataSet
Dim HisDatos As DataSet1/Socios"oJ
4 Almacenamos en Rl, la in8ormaciSn %el DataSet 2ara
4 el AI) = "111111"
HisDatos = %tSet/Socios/)in%,-AI)("111111")
4 Ho%i8icaremos el cam2o C?
HisDatos/C? = "2X022"
4 Deshabilitamos como me%i%a %e seg!ri%a% el botSn
,!tton1/nable% = )alse
n% S!b
?ri5ate S!b ,!tton2+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton2/ClicQ
I8 %tSet/HasChanges 1hen
4 l DataSet tiene cambios
4 Declaramos !n ob#eto DataSet
Dim %tSetHo%i8ica%o As DataSet
4 'e 2asamos los %atos mo%i8ica%os en el DataSet original
%tSetHo%i8ica%o = %tSet/;etChanges
4 Act!ali&amos el DataSet I!e ha cambia%o a tra5Rs %el DataA%a2ter
SIlDataA%a2ter1/F2%ate(%tSetHo%i8ica%o)
466
4 Ace2tamos los cambios en el DataSet 2ara
4 seg!ir traba#an%o con Rl 2or e#em2lo
%tSet/Acce2tChanges()
4 Hostramos !n mensa#e en 2antalla in%ican%o I!e
4 se han mo%i8ica%o los %atos
Hessage,oG/ShoJ("'os cambios %el DataSet han si%o" P 5bCr'8 P
"act!ali&a%os en la base %e %atos")
4 Deshabilitamos como me%i%a %e seg!ri%a% el botSn
,!tton2/nable% = )alse
lse
4 l DataSet no tiene cambios
Hessage,oG/ShoJ("Ao ha- cambios en el DataSet")
n% I8
n% S!b
?ri5ate S!b ,!tton3+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton3/ClicQ
4 ATa%imos !na n!e5a 8ila con %atos al DataSet ti2a%o
%tSet/Socios/A%%Socios"oJ("111112", "HarKa", "S6nche&", ""o%rKg!e&",
"123123.", "maria\c!enta%ecorreo/com", "CU San )ernan%o, 13", ",arcelona",
",arcelona", "0X001")
4 Act!ali&amos los %atos a tra5Rs %el DataA%a2ter
SIlDataA%a2ter1/F2%ate(%tSet)
4 Deshabilitamos el botSn %e aTa%ir %atos
,!tton3/nable% = )alse
4 Habilitamos el botSn %e eliminar %atos
,!tton./nable% = 1r!e
4 Hostramos !n mensa#e in%ican%o I!e la
4 acciSn se ha reali&a%o correctamente
Hessage,oG/ShoJ(""egistro aTa%i%o correctamente")
n% S!b
467
?ri5ate S!b ,!tton.+ClicQ(,-$al sen%er As S-stem/0b#ect, ,-$al e As
S-stem/5entArgs) Han%les ,!tton./ClicQ
4 ,orramos la 8ila aTa%i%a
%tSet/Socios/)in%,-AI)("111112")/Delete()
4 Act!ali&amos los %atos a tra5Rs %el DataA%a2ter
SIlDataA%a2ter1/F2%ate(%tSet)
4 Hostramos !n mensa#e in%ican%o I!e la
4 acciSn se ha reali&a%o correctamente
Hessage,oG/ShoJ(""egistro elimina%o correctamente")
4 Deshabilitamos el botSn %e eliminar
,!tton./nable% = )alse
n% S!b
n% Class
Nuestro ejemplo en ejecucin es el que se muestra en la figura 16.
jemplo del uso de DataAdapter y Data!et tipado con todas las acciones de insercin y eliminacin de datos incluidas
Figura 16
Como vemos, el uso del DataSet tipado, posee grandes ventajas sobre los DataSets
no tipados, permitindonos trabajar con datos de forma muy rpida y sencilla.
La parte ms compleja quizs, es la preparacin del esquema de datos, pero una vez
realizada esta tarea, el trabajo con los datos es asombrosamente rpida y segura.

468

-ntroducci(n
Visual Basic 2005 Express proporciona a los desarrolladores un conjunto de
herramientas y asistentes que facilitan enormemente el trabajo y ahorran grandes
cantidades de tiempo en el desarrollo de diferentes aplicaciones.
De los asistentes o herramientas que nos proporcionan mayor rendimiento en el
entorno de desarrollo rpido de Microsoft, est la que nos permite trabajar con fuentes
de datos como los datos de una aplicacin tpica maestro detalle.
Entre otras cosas, nos centraremos en esta accin, que ser la que veremos en detalle
a continuacin.
%(dulo B ? Cap!tulo 3

1. Que son los datos maestro detalle?
2. Configurando la fuente de datos
3. Preparando el origen de datos
4. Incrustando los datos maestro detalle
5. Manipulando los datos maestro detalle
469

-ntroducci(n
Visual Basic 2005 Express proporciona a los desarrolladores un conjunto de
herramientas y asistentes que facilitan enormemente el trabajo y ahorran grandes
cantidades de tiempo en el desarrollo de diferentes aplicaciones.
De los asistentes o herramientas que nos proporcionan mayor rendimiento en el
entorno de desarrollo rpido de Microsoft, est la que nos permite trabajar con fuentes
de datos como los datos de una aplicacin tpica maestro detalle.
Entre otras cosas, nos centraremos en esta accin, que ser la que veremos en detalle
a continuacin.
%(dulo B ? Cap!tulo 3

1. Que son los datos maestro detalle?
2. Configurando la fuente de datos
3. Preparando el origen de datos
4. Incrustando los datos maestro detalle
5. Manipulando los datos maestro detalle

470

%(dulo B ? Cap!tulo 3
@. 78u0 son los datos %aestro "etalle9
El desarrollador de aplicaciones que debe trabajar con datos y fuentes de datos
relacionadas entre s, encuentra con frecuencia problemas de desarrollo en
aplicaciones con datos interrelacionados.
Adems, este tipo de aplicaciones, consumen gran parte del tiempo de desarrollo y
son por lo general, acciones repetitivas.
Supongamos como ejemplo general, la tabla Socios de un videoclub.
Adems, relacionemos los socios del videoclub, con una tabla *l9uileres, para saber si
un socio determinado tiene pelculas alquiladas, y en ese caso, saber cules.
Este sencillo ejemplo, es un claro exponente de una aplicacin que relaciona datos
maestro detalle.
Ambas tablas deben estar relacionadas para recopilar la informacin que se necesite
en un momento dado.
Los datos maestros seran expuestos por los socios del videoclub, mientras que los
datos detalle estaran relacionados con los datos de los alquileres de los socios.
En nuestro caso, vamos a cambiar las palabras maestro y detalle por padre e hijo, y a
partir de ahora, nos referiremos a padre como la tabla Socios, e hijo como la tabla
*l9uileres. De esta forma, ubicaremos sin problemas ambos conceptos dentro del
entorno de #isual Basic 2BBC %&press, ya que ste tiene alguna ligera connotacin que
podra infundirnos a error como observar ms adelante.
Por suerte, #isual Basic 2BBC %&press nos proporciona un conjunto de herramientas,
que hace que realizar una aplicacin Windows con todas las caractersticas de una
aplicacin maestro detalle, sea un autntico juego de nios, que nos llevar
aproximadamente un minuto de nuestro tiempo como mucho.
No me cree?. Contine el captulo, y se sorprender de lo que #isual Basic 2BBC
%&press puede hacer por usted.
471

%(dulo B ? Cap!tulo 3
1. Configurando la fuente de datos
Trabajar con fuentes de datos requiere como tarea inicial, que tengamos listo y
preparado un orgen de fuentes de datos vlido.
Para esta tarea, deberemos configurar la fuente de datos que vamos a utilizar, algo
que vamos a aprender a hacer a continuacin.


Configurando el origen de la fuente de datos
Iniciaremos una nueva aplicacin Windows con #isual Basic 2BBC %&press y
seleccionaremos el men /atos 6 Mostrar or,'enes de datos como se indica en la
figura 1.
Men? para mostrar los or@"enes de datos
Figura 1
En este punto, aparecer una ventana como la que se muestra en la figura 2.
472
&entana de or@"enes de datos
Figura 2
Como podemos apreciar, la ventana no tiene por defecto ningn origen de datos
asignado, adems, esta ventana inicialmente, no est anclada a ningn sitio del
entorno.
Para situarla en un lugar especfico del entorno, haga clic sobre la ventana y arrstrela
sobre la parte en la que desee situarla, como se indica por ejemplo, en la figura 3.
473
La ventana or@"enes de datos podemos situarla dnde deseemos dentro de &isual #asic ,++- 5press
Figura 3
En este punto, la ventana de orgenes de datos, quedar anclada en el entorno de
desarrollo, como se muestra en la figura 4.
474
La ventana or@"enes de datos anclada en &isual #asic ,++- 5press
Figura 4
Cada uno, puede situar esta ventana dnde considere oportuno. En mi caso la he
situado entre las ventanas del %&plorador de soluciones y de +ropiedades, pero
podemos situarla dnde consideremos opotuno.
Sobre la configuracin del orgen de datos, haga clic sobre la opcin *gregar nueo
origen de datos... como se indica en la figura 5.
:pcin para a"re"ar un nuevo ori"en de datos
Figura 5
Aparecer una ventana como la que se muestra en la figura 6 en la cul indicaremos el
lugar de dnde la aplicacin obtendr los datos, y que en nuestro caso ser de una
Base de datos.
475
Como tipo de ori"en de datos ele"iremos una #ase de datos
Figura 6
Una vez seleccionado la opcin de Base de datos como tipo de origen de datos,
pulsaremos el botn Si'uiente.
En la siguiente ventana, eligiremos la conexin de la base de datos que vamos a
utilizar, o pulsaremos sobre el botn Nueva cone;in... sino tenemos seleccionada la
conexin que queremos utilizar.
En la figura 7, podemos ver como hemos establecido la conexin con nuestra fuente
de datos, que utilizaremos en nuestro ejemplo de creacin de la aplicacin de acceso a
datos maestro detalle.
476
&entana dnde ele"imos la cone5in de datos
Figura 7
A continuacin, haremos clic en el botn Si'uiente.
En la nueva ventana que aparece ahora dentro del asistente para la creacin del
origen de datos, indicaremos el nombre de la cadena de conexin que crearemos. En
nuestro caso, no modificaremos el nombre de la cadena de conexin, dejndola por
defecto como se muestra en la figura 8.
477
Asi"namos un nombre para el nombre de la cadena de cone5in
Figura 8
A continuacin, haremos clic sobre el botn Si'uiente.
En este punto, el asistente se conecta a la base de datos para recuperar la informacin
de la base de datos y mostrarla en la ventana del asistente como se muestra en la
figura 9.
478
&entana con los objetos de la base de datos seleccionada
Figura 9
A continuacin, despliegue el objeto Ta#las y seleccione las tablas *l9uileres y Socios
como se indica en la figura 10.
479
!eleccin de los objetos de la base de datos seleccionada
Figura 10
Una vez que hemos seleccionado los objetos de la base de datos, haremos clic sobre el
botn Finali@ar para que el asistente concluya las opciones aadidas al asistente.
La ventana del origen de datos, quedar ahora configurado de una forma similar a la
que se presenta en la figura 11.
&entana de ori"en de datos con la confi"uracin a2adida
Figura 11
A partir de aqu, deberemos preparar las tablas del origen de datos para que se
comporten como autnticos datos e informaciones maestro detalle.
Esto es lo que veremos en el siguiente mdulo.
480


%(dulo B ? Cap!tulo 3
A. ,reparando el origen de datos
Ya hemos aprendido a aadir nuestro origen de datos, y ahora aprenderemos a
prepararlo para poder utilizarlo posteriormente en la aplicacin Windows.
La preparacin del origen de datos, nos permitir seleccionar que tabla o datos
queremos que acten como maestro y cuales como detalle, o dicho de otra forma, que
datos queremos que sean padre y cuales hijo.
Nuestro objetivo principal es mostrar la tabla *l9uileres como tabla hijo y la tabla
Socios como padre de la tabla anterior.
Prepararemos e incrustaremos primero la tabla Socios dentro del formulario Windows
como Detalle de la informacin, y posteriormente insertaremos la tabla *l9uileres
dentro del formulario.
Por ltimo, asignaremos alguna relacin que permita trabajar con las dos tablas en
nuestro formulario Windows sin perder la conexin entre ambas tablas y
permitindonos acceder a la informacin que nos proporciona dicha relacin.


,reparando la tabla padre
Lo primero que haremos ser preparar la tabla padre para poderla aadir al formulario
Windows.
Por esa razn, haremos clic sobre la tabla Socios de la ventana de OrIgenes de datos
como se indica en la figura 1.
481
$abla !ocios de la ventana de or@"enes de datos
Figura 1
En la ventana de OrIgenes de datos y en concreto con la tabla Socios desplegada,
centraremos nuestra atencin en el campo +I: como se indica en la figura 2.
Campo ;I( de la tabla !ocios
Figura 2
Pulse sobre la lista desplegable que aparece a la derecha del campo +I: y seleccione
la opcin Label como se indica en la figura 3.
Lista desple"able con la opcin Label seleccionada como campo de la tabla desple"ada
Figura 3
En este caso, la ventana de OrIgenes de datos quedar informada tal y como se indica
en la figura 4.
482
Campo ;I( modificado en la ventana de :r@"enes de datos
Figura 4
A continuacin, haremos clic sobre la tabla Socios como se indica en la figura 5, y
posteriormente pulsaremos sobre la lista desplegable que aparece a la derecha de la
tabla.
$abla !ocios seleccionada en la ventana de :r@"enes de datos
Figura 5
Si hacemos clic sobre la lista desplegable, aparecer una lista de opciones o
posibilidades, para indicar cmo queremos que sean los campos de la tabla
seleccionada con respecto a que tipo de controles queremos que sean.
Esto es lo que se indica en la figura 6.
Lista desple"able de la tabla !ocios de la ventana de :r@"enes de datos
Figura 6
Por defecto, una tabla queda determinada con un icono que representa el control
Data1rid#ie!, aunque se puede modificar la representacin que deseamos tengan los
datos dentro de un formulario seleccionando cualquiera de las opciones que tenemos
de la lista desplegable.
Estas opciones pueden ser cualquiera de las siguientes:
Representa los datos volcados dentro de un control Data1rid#ie!
483
Representa los datos volcados dentro de controles estndar como Te&tBo& u otros
controles para reflejarla como Detalle de la informacin
No representa ningn control como tipo de control de volcado de datos
En el caso de la tabla Socios que usaremos como tabla padre, cambiaremos la
representacin por defecto de Data1rid#ie! para indicarle que nos represente la
informacin en controles, tal y como se indica en la figura 7.
$abla !ocios seleccionada en la ventana de :r@"enes de datos como Detalle
Figura 7
Ahora que tenemos la tabla maestra ya preparada, pasaremos a preparar la tabla hija.


,reparando la tabla #ia
Ahora que ya tenemos preparada la tabla tabla padre, prepararemos la tabla hija de
los alquileres de las pelculas de video, para poder usar su informacin dentro del
formulario Windows.
Por esa razn, haga clic sobre la tabla *l9uileres de la ventana de OrIgenes de datos
como se indica en la figura 8.
$abla Alquileres de la ventana de or@"enes de datos
Figura 8
Dentro de la ventana de OrIgenes de datos y en concreto de la tabla *l9uileres
desplegada, centraremos nuestra atencin en el campo AlAuilerID y .ocio+I: como
se indica en la figura 9.
484
Campos AlquilerID y !ocio;I( de la tabla Alquileres
Figura 9
Sobre el campo AlAuilerID y .ocio+I:, haremos una pequea modificacin.
Pulse sobre la lista desplegable que aparece a la derecha del campo AlAuilerID y
.ocio+I: y seleccione la opcin Label como se indica en la figura 10.
Lista desple"able de opciones de un campo de la tabla desple"ada
Figura 10
De esta manera, el campo AlAuilerID y .ocio+I: quedarn modificados en la
ventana OrIgenes de datos como se indica en la figura 11.
Campo AlquilerID y !ocio;I( modificados en la ventana de :r@"enes de datos
Figura 11
A continuacin, haremos clic sobre la tabla *l9uileres como se indica en la figura 12, y
posteriormente pulsaremos sobre la lista desplegable que aparece a la derecha de la
tabla.
485
$abla Alquileres seleccionada en la ventana de :r@"enes de datos
Figura 12
Nos aseguraremos que est seleccionada la opcin Data1rid#ie! que es la que
aparece por defecto.
Esto es lo que se indica en la figura 13.
n la tabla Alquileres8 nos ase"uraremos de seleccionar la opcin Data<rid&ie7
Figura 13
Una vez que tenemos las tabla maestra y detalle preparadas para utilizarlas, las
aadiremos al formulario Windows para que tengan el funcionamiento esperado.

486

%(dulo B ? Cap!tulo 3
B. -ncrustando los datos maestro detalle
Ya sabemos como crear un origen de datos, tambin sabemos como preparar los datos
maestro y detalle, y por ltimo, lo que nos queda es insertar esos datos en el
formulario, y relacionar todos sus datos para que funcionen de la forma esperada.
A continuacin, veremos como llevar a cabo esta tarea y aprenderemos a hacerlo
posible de forma muy rpida y sencilla.


-ncrustando la tabla padre en el formulario
Nuestra primera accin, ser incrustar en el formulario los datos o tabla padre, que en
nuestro caso es la formada por la tabla Socios.
Para situar los datos de la tabla Socios dentro de un formulario y en concreto como
una informacin de detalle, bastar con arrastrar y soltar la tabla Socios sobre el
formulario como se indica en la figura 1.
487
9ara presentar la informacin como detalle8 arrastraremos la tabla !ocios de la ventana :r@"enes de datos sobre el
formulario 6indo7s
Figura 1
Observaremos que #isual Basic 2BBC %&press, generar por nosotros un conjunto de
componentes y controles, que por defecto tendr una apariencia similar a la que se
presenta en la figura 2.
488
Controles y Componentes de la tabla maestra a2adidos al formulario 6indo7s
Figura 2
Observe por un momento, que el campo +I: que declaramos como Label en la
ventana de OrIgenes de datos, aparece como tal en el formulario, tal y como se indica
en la figura 3.
Campo ;I( de la tabla8 representado como un control Label en el formulario 6indo7s
Figura 3
Si ejecutamos nuestra aplicacin, observaremos que esta acta como una tpica
aplicacin de acceso a datos que nos permite navegar a travs de los campos de la
tabla Socios, tal y como se indica en la figura 4.
489
Aplicacin en ejecucin de la tabla de detalle incrustada en el formulario 6indo7s
Figura 4
A continuacin, insertaremos en el formulario la tabla *l9uileres y relacionaremos
ambas tablas para que se muestren los datos relacionados, dentro del formulario
Windows.


-ncrustando la tabla #ia en el formulario
Ya tenemos la tabla padre insertada en nuestro formulario Windows. Nuestra segunda
accin, ser la de incrustar en el formulario los datos o tabla hoja, que en nuestro
caso es la formada por la tabla *l9uileres, la cul adems, posee una relacin entre
campos con la tabla Socios insertada anteriormente.
Para llevar a cabo esta accin arrastraremos y soltaremos la tabla *l9uileres sobre el
formulario como se indica en la figura 5.
490
9ara presentar la informacin de la tabla Alquileres8 arrastraremos la tabla de la ventana :r@"enes de datos sobre el
formulario 6indo7s
Figura 5
Observe que #isual Basic 2BBC %&press, genera por nosotros ms componentes y
controles, que por defecto tendr una apariencia similar a la que se presenta en la
figura 6.
491
Controles y Componentes de la tabla maestra y detalle a2adidos al formulario 6indo7s
Figura 6
Como podemos observar, el entorno de trabajo ha hecho por nosotros el trabajo ms
complejo para representar los datos de forma rpida y sencilla.
El esquema de datos tipados, apareca ya en nuestro proyecto cuando asignamos el
correspondiente origen de datos.
Ahora lo que ha ocurrido, es que al arrastrar y soltar la tabla padre Socios de la
ventana de OrIgenes de datos, en el entorno se ha aadido un componente de nombre
(SD$#ideoDataSet que es el que permitir relacionar el DataSet tipado con nuestros
datos.
Este componente ser usado por la relacin maestro detalle de las dos tablas aadidas
al formulario.
En la figura 7, podemos ver el esquema aadido a nuestro proyecto, y el componente
del que estamos hablando.
492
squema del Data!et tipado a2adido al proyecto y su componente de relacin
Figura 7
Ejecute la aplicacin y observe el comportamiento de la misma.
Observar por lo tanto, que los datos entre detalle y maestra, no estn relacionados.
Si navegamos a travs de los datos de detalle a travs del objeto
SociosBinding$aigator, el control Data1rid#ie! no representa la relacin de los datos
seleccionados.
Esto es lo que se muestra en la figura 8.
jecucin de la aplicacin confirmando que los datos mostrados no est>n relacionados
Figura 8
A continuacin, la tarea que nos queda para completar el correcto funcionamiento de
nuestra aplicacin, es la de relacionar la tabla detalle y la tabla maestra entre s, para
que los datos que se muestran en la aplicacin, estn relacionados entre s.

Eelacionando la tabla padre con la tabla #ia
La tarea ms sencilla es la de relacionar la tabla detalle con la tabla maestra. Es una
tarea sencilla, porque #isual Basic 2BBC %&press nos proporciona las herramientas
necesarias para simplificar al mximo esta tarea.
493
Para llevar a cabo esta tarea, haga clic sobre el control Data1rid#ie! que corresponde
a los datos de la tabla maestra, y acceda a la ventana de +ropiedades.
Dentro de la ventana de +ropiedades, acceda a la propiedad DataSource como se
indica en la figura 9.
9ropiedad Data!ource del control Data<rid&ie7 de la informacin maestra
Figura 9
Despliegue esta propiedad, y de la lista desplegable que aparece, seleccione la opcin
:?BAlAuileresB.ocios como se indica en la figura 10.
Asi"nacin de la clave de relacin entre las tablas
Figura 10
494
Cuando se asigna el campo de relacin de las tablas, dentro de la aplicacin se aade
esta relacin para que cuando naveguemos entre los datos de la tabla Socios aparezca
toda la informacin de la tabla *l9uileres relacionada con la tabla Socios.
Esto de lo que hablamos, est supeditado por el componente
)K-*l9uileres-SociosBindingSource que es lo que se indica en la figura 11.
Controles y componentes incluido el de relacin entre tablas8 a2adidos al formulario 6indo7s
Figura 11
Para finalizar, ejecutaremos nuestra aplicacin y comprobaremos que el
funcionamiento de esta, incluida la relacin entre tablas, funciona como esperbamos.
En la figura 12, podemos observar el comportamiento de nuestra aplicacin en
ejecucin.
495
Aplicacin en ejecucin8 mostrando la correcta relacin entre las tablas
Figura 12

496
%(dulo B ? Cap!tulo 3
3. %anipulando los datos maestro detalle
Obviamente, los datos maestro detalle no nos sirve nicamente para insertar las
tablas de datos en un formulario, mostrarlos y navegar por ellos.
Adems de esto, podemos tambin manipular los datos maestro detalle, modificarlos,
actualizarlos, borrarlos, sin hacer ninguna accin adicional.
El control Binding$aigator ya proporciona todas las caractersticas necesarias para
realizar estas acciones.
Podemos personalizar el control para permitir o denegar estas acciones.
Adems, dentro de la ventana de OrIgenes de datos, podemos seleccionar diferentes
campos de las tablas y cambiar el tipo de control en el que queremos representar sus
datos.
A continuacin veremos un breve ejemplo de como manipular datos para que nos sirva
de aprendizaje de cmo hacer esto posible.


%odificando datos
Ejecute la aplicacin de ejemplo que hemos diseado hasta ahora y sitese en alguno
de sus campos.
Centrndonos en la informacin de la tabla Socios, cambiaremos un campo
determinado, como el que se muestra en la figura 1.
Modificaremos el valor de un campo para que nos sirva de ejemplo
Figura 1
Acto seguido, cuando hayamos realizado la modificacin, haremos clic sobre la opcin
de 1uardar datos, tal y como se muestra en la figura 1.
497
:pcin del control #indin";avi"ator para "uardar los datos modificados
Figura 2
Como vemos, la manipulacin de datos es realmente sencilla y en la relacin de datos
mostrada, no tiene porqu presentarnos ninguna dificultad.


-nsertando y eliminando datos
Si queremos agregar datos, deberemos hacer clic sobre la opcin *gregar nueo del
control Binding$aigator como se muestra en la figura 3.
A2adir un re"istro nuevo es realmente sencillo
Figura 3
De la misma manera funciona el mecanismo para eliminar un registro, tal y como se
muestra en la figura 4.
liminar un re"istro de forma r>pida
Figura 4
Recuerde pulsar sobre el icono si quiere que los cambios y
modificaciones realizadas se mantengan. Pulsando sobre ese icono, la
accin de manipulacin de datos se lanza contra la base de datos.
498