Programación Con Visual Basic 2008 (McGraw-Hill)
Programación Con Visual Basic 2008 (McGraw-Hill)
Programación Con Visual Basic 2008 (McGraw-Hill)
Visual Basic
claramente y darse la oportunidad de probarlos. Este
libro le da estos elementos. No slo conseguir una tanto como ste. Excelente
firme comprensin sobre conceptos de desarrollo de software en cobertura, perfecto para la
Visual Basic, tambin tendr prctica real al disear, construir y
audiencia a la que est
desplegar una aplicacin completa orientada a base de datos.
dirigido. Descripciones
2008
Cada captulo de Programacin con Visual Basic 2008 ofrece
explicaciones claras, repletas de cdigo de ejemplo para concisas, claras, exactas.
ayudarle a construir su aprendizaje durante el proceso de Es un ganador.
desarrollo. Con esta obra completa, usted: -Ken Getz
Consultor senior
Adquirir experiencia prctica en el desarrollo de aplicaciones MCW Technologies
.NET, desde el diseo hasta la implementacin.
Disear bases de datos con SQL Server y ADO.NET.
Construir aplicaciones de escritorio complejas con Tim Patrick es arquitecto de software
formularios de Windows y aplicaciones Web con ASP.NET. y desarrollador; tiene 25 aos de
experiencia en diseo y construccin
Dominar las nuevas caractersticas de VB 2008 como de soluciones personalizadas de
expresiones lambda y tipos null. software. MVP de Microsoft y
Acelerar los procesos con consultas LINQ y generacin desarrollador de soluciones
de XML dinmico. certificado de Microsoft, Tim ha
publicado cinco tutoriales y
Descubrir cmo dar licencias, documentar, implementar
referencias sobre desarrollo de
y dar soporte a sus aplicaciones.
Visual Basic, junto con varios
Extender an ms su aprendizaje, usando el cdigo fuente artculos. Entre sus libros se incluyen
de aplicaciones incluido. Visual Basic 2005 in a Nutshell y
Visual Basic 2005 Cookbook.
Obtendr la mentalidad de un desarrollador al adquirir
habilidades de programacin cotidianas.
Patrick
978-607-15-0248-3
Tim Patrick
Programacin con Visual Basic 2008
Tim Patrick
Traduccin
Eloy Pineda Rojas
Traductor profesional
Educacin
Educacin
ISBN: 978-607-15-0248-3
Authorized translation of the English edition of Programming Visual Basic 2008.
ISBN 9780596518431. Tim Patrick. This translation is published and sold
by permission of OReilly Media, Inc., the owner of all rights to publish and sell the same.
1234567890 109876543210
Impreso en Mxico Printed in Mexico
Prlogo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv
1. Introduccin a .NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
Antes de .NET 1
De nuevo, la presentacin de .NET 2
El objeto en .NET 3
Las partes de .NET Framework 7
Del cdigo fuente a EXE 16
Temas relacionados con Visual Studio y Visual Basic 17
Visual Studio 2008 18
Resumen 22
Proyecto 23
vii
viii | Contenido
Contenido | ix
x | Contenido
Contenido | xi
xii | Contenido
Contenido | xiii
ndice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725
xiv | Contenido
Bienvenido a Programacin con Visual Basic 2008! S que va a disfrutarlo. Ya lo he ledo cinco
veces. Es probable que se encuentre ansioso de llegar al captulo 1, pero le recomiendo que lea
este prlogo para asegurarse de que pag por el libro correcto.
xv
xvi | Prlogo
Prlogo | xvii
xviii | Prlogo
Prlogo | xix
Bienvenido a .NET! Tambin podra decir Bienvenido al universo, porque .NET es grande
como el universo. Y es complejo. Y est lleno de hoyos negros y otras cosas que no siempre
tienen sentido. Pero resulta que es un sistema fantstico (.NET, no el universo) para desarrollar
aplicaciones de software.
El .NET Framework fue desarrollado en un vaco (a diferencia del universo); Microsoft lo desa
rroll, junto con sus lenguajes de desarrollo (sobre todo C# y Visual Basic) para atender varios
de los problemas que padecan los desarrolladores y usuarios del software de Windows. Para
comprender por completo por qu .NET era necesario, necesitamos hacer un corto viaje por los
caminos de la historia de la computadora.
Antes de .NET
Las computadoras de propsito general han existido desde mediados del siglo xx. Sin embargo,
eran inaccesibles para la mayora porque: (a) costaban millones de dlares; (b) consuman enor
mes cantidades de energa elctrica; (c) el mantenimiento y la programacin slo podan reali
zarlos especialistas capacitados, y (d) tendan a entrar en conflicto con los muebles de la sala.
Treinta aos despus, IBM desarroll la idea de la computadora personal. Estas computadoras
de escritorio representaron un gran avance en tecnologa, pero slo una minora las us alguna
vez. Seguan siendo costosas (miles de dlares) y el mantenimiento y la programacin an re
queran una importante inversin en entrenamiento. Las PC de IBM an se vean abominables
junto a los muebles de la sala.
Luego surgi la Macintosh de Apple. Con su brillante diseo y su funcionalidad amigable, llev
la alegra de la computacin a las masas. Y aunque la programacin no siempre era sencilla,
brind agradables resultados. No maravilla que Microsoft decidiera copiar (perdn, quise decir
mejorar) su funcionalidad.
El objeto en .NET
Para comprender totalmente el desarrollo del software en .NET, debe entender qu es un objeto.
(Si est familiarizado con la programacin orientada a objetos, puede omitir lo siguiente y pasar
a la prxima seccin, aunque se perder un contenido estupendo.) A pesar de que parte de la
informacin de esta seccin tambin aparece en el captulo 8, es tan importante analizar .NET
que una parte de ella tambin aparecer aqu.
El objeto en .NET | 3
Por lo general, es fcil usar los miembros pblicos de una TV: la perilla de encendido, el selector
de canales, el control de volumen, etc. Son los conductos mediante los cuales el usuario controla
los valores de datos de la TV (su salida de video y audio). Tambin hay miembros ocultos den
tro de la TV; podra usar estos miembros para mejorar la calidad de imagen y sonido, aunque
esto sera una mala idea para la mayora de los usuarios. No querr meterse con los elementos
internos de su televisor, crame. De la misma manera, un objeto no querr que cdigo externo
al objeto se mezcle con sus miembros internos, excepto si lo hace a travs de los miembros pblicos.
No me preocupa la manera en que la TV funciona internamente, siempre y cuando obtenga las
imgenes y el sonido usando los controles (encendido, canales, volumen).
Objetos e interfaces
Los miembros pblicos de un objeto representan su interfaz. Si el cdigo externo del objeto
quiere manipular los datos que pertenecen a ese objeto, utiliza los miembros de la interfaz. No
tiene que imaginar los miembros ocultos o la manera en que funcionan, y eso es correcto. Sobre
todo, es correcto si esos miembros internos cambian alguna vez por una razn, lo que sucede con
ms frecuencia de lo que se imagina. Considere la manera en que los elementos internos de la TV
han cambiado en los ltimos 30 aos. He aqu un dibujo de la TV que mi familia tena cuando
era nio. Comprela con las TV de panel plano modernas de hoy en da (vase la figura 1-2).
La TV de mi familia era estupenda. Tena un radio estereofnico de alta fidelidad, una tornamesa
que reproduca discos de 33 1/3, 45 y 78 rpm, y una pantalla grande de 19 pulgadas en blanco y
negro, con un despliegue claro como un cristal. Dos nios podan ocultarse tras ella y jugar a las
escondidas. Y mi amigo que tena el mismo modelo afirmaba que poda dibujar lneas permanen
tes realmente asombrosas en la pantalla con un imn. A quin le importaba que los paneles de las
bocinas parecieran una alfombra gastada? A quin le importaba que la unidad ocupara hasta 30%
del espacio de la sala? A quin le importaba que pudieran cocinarse salchichas sobre ella por el
calor que generaban los bulbos? Era ms que una TV; se trataba de un centro de entretenimiento.
El objeto en .NET | 5
Ahora comprela con la sosa pantalla plana de la derecha. Si la ve de cerca, notar que la interfaz
de la TV no ha cambiado mucho en tres dcadas. An tiene controles para encendido y selec
cin de canales (aunque ya han desaparecido los controles para lneas horizontales y verticales).
Lo que ha cambiado es la configuracin interna. Ya se fueron los bulbos que zumbaban, todos
ellos reemplazados con transistores eficientes y componentes de estado slido. Pero no tiene
mucha diferencia para el espectador, porque la interfaz pblica sigue siendo la misma.
En la programacin orientada a objetos, stos desarrollan su trabajo de la misma manera. Siem
pre y cuando la interfaz pblica siga siendo la misma, pueden cambiar el cdigo actual del objeto
y el sistema de almacenamiento de datos interno (a lo que se le conoce tambin como implemen-
tacin del objeto), pero no tiene impacto en la aplicacin general.
Objetos e instancias
La interfaz y la implementacin de un objeto en realidad slo representa su diseo; hay partes
que el programador crea mediante el cdigo fuente. Existen incluso antes de que se compile el
programa y se instalen en la computadora del usuario. En realidad, en este nivel, los objetos ni
siquiera son conocidos como objetos. En la mayora de los lenguajes (incluido Visual Basic), la
palabra clase indica la implementacin de la interfaz de un objeto.
Una vez que su aplicacin est instalada en una computadora y se inicia, el cdigo crea instancias
de la clase para almacenar datos reales en memoria. Estas instancias son los objetos reales del
desarrollo de la programacin orientada a objetos. Dependiendo de la manera en que se escribe
su cdigo, podra usarse la implementacin de una sola clase para crear uno o cientos de objetos
en memoria al mismo tiempo.
S, todo un galimatas. Pero es correcto, porque satisface los requisitos de la Asociacin Interna
cional de Libros de Cmputo de que todos los captulos 1 incluyan el ejemplo de cdigo Hola,
mundo. Adems, el CLR lo comprende, y eso es lo que realmente cuenta en .NET. Siempre y
cuando tenga su cdigo en IL, .NET lo procesar. El compilador de Visual Basic slo genera el IL
automticamente. Otros compiladores de lenguaje .NET, incluido C#, tambin producen IL. In
cluso puede escribir su propio cdigo IL, pero es probable que est leyendo el libro equivocado para
eso. Slo ponga a descansar su mente, ste ser el ltimo fragmento de IL que ver en este libro.
* Si quiere leer un libro realmente fascinante acerca de cmo se forman las operaciones complejas de software y hardware a
partir de los usos ms bsicos de 0 y 1, lea Code: The Hidden Language of Computer Hardware y Software, de Charles Petzold
(Microsoft Press).
Windows
Forms
Form
Todas las clases y los tipos existen en algn lugar de la jerarqua, aunque no todas las clases des
cienden de System. Muchas de las caractersticas de soporte especficas de Visual Basic aparecen
en el espacio de nombres Microsoft.VisualBasic, que tiene Microsoft como nodo raz
en lugar de System. Cuando crea proyectos nuevos en Visual Basic, el nombre del proyecto
es, como opcin predeterminada, un nuevo nodo de nivel superior en la jerarqua. Si crea una
nueva aplicacin de Windows llamada WindowsApplication1, el formulario Form1 prede
terminado tiene el siguiente nombre plenamente calificado:
WindowsApplication1.Form1
Este nuevo espacio de nombres de la aplicacin no slo es un apndice de segunda clase que
cuelga del espacio de nombres System. Est plenamente integrado en la jerarqua completa de
espacio de nombres de .NET; el espacio de nombres WindowsApplication1 es un nodo raz,
al igual que los nodos raz System y Microsoft. Visual Basic incluye caractersticas que le per
miten modificar el espacio de nombres predeterminado para su aplicacin, o coloca una de las
clases de la aplicacin en un espacio de nombres especfico. Incluso puede colocar las clases de
su aplicacin en la rama del espacio de nombres System. Al cambiar WindowsApplication1 a
System.MiSuperApl se mueve Form1 a:
System.MiSuperApl.Form1
Si su aplicacin es, en realidad, una biblioteca o un componente destinado para usar en progra
mas, las clases de su aplicacin aparecern en el espacio de nombres que especifique cuando el
otro programa cargue su componente en el rea de su aplicacin. Su cdigo parecer parte de los
espacios de nombres proporcionados por Microsoft. No es estupendo?
Aunque puede agregar sus clases al espacio de nombres System, terminar con la misma mo
lestia que otros programadores de .NET. Se supone que el espacio de nombres System es para
las caractersticas del sistema (lase: proporcionadas por Microsoft), y eso es todo. Adems,
es posible que dos vendedores usen la misma ruta del espacio de nombres. As que, para evitar
posibles conflictos de espacio de nombres y miradas indiscretas de otros programadores, debe
asignar a las clases de su aplicacin el siguiente nombre:
NombreEmpresa.NombreAplicacin.NombreClase
Ensamblados y manifiestos
Un ensamblado es una unidad de implementacin de las partes de la aplicacin o biblioteca
.NET. En 99.9% de los casos, un ensamblado es simplemente un archivo ejecutable de .NET (un
archivo .exe) o una biblioteca de clases de .NET y de otros tipos (un archivo .dll). Es posible dividir
un ensamblado entre varios archivos, pero por lo general se dedica un archivo a un ensamblado.
Lo que convierte a un archivo .exe o .dll ordinario en un ensamblado es la presencia de un
manifiesto. En el caso de ensamblados de un solo archivo, el manifiesto aparece en el archivo;
tambin puede aparecer en un archivo independiente. El manifiesto es un fragmento de datos que
presenta una lista de detalles importantes acerca del ensamblado, incluido su nombre, informacin
de versin, datos culturales predeterminados, informacin sobre ensamblados y tipos externos de
referencia, y una lista de todos los archivos contenidos en el ensamblado. El CLR no reconocer
un ensamblado sin su manifiesto, de modo que no lo pierda.
Los ensamblados pueden incluir un nombre fuerte opcional. Esto ayuda a asegurar la integridad
y autenticidad de un ensamblado mediante una firma digital adjunta al manifiesto. El nombre
fuerte utiliza criptografa de clave pblica para garantizar que el ensamblado es nico y no se ha
modificado. Visual Studio y .NET Framework incluyen herramientas que permiten agregar un
nombre fuerte a un ensamblado.
Cuando implemente su aplicacin, por lo general colocar todos los archivos del ensamblado,
de configuracin y relacionados y especficos de su aplicacin en el directorio de instalacin de
la aplicacin, al igual que en los das del Jursico antes de .NET. Los ensamblados compartidos
que estn diseados para que los use ms de una aplicacin en una sola mquina puede almace
narse en la cach global de ensamblados (GAC, Global Assembly Cache). Todos los ensamblados
colocados en la GAC deben tener nombres fuertes. Algunos sistemas permiten que slo los ad
ministradores del sistema agreguen ensamblados a la GAC.
Metadatos y atributos
Los ensamblados estn determinados por la letra m. Adems de manifiestos y miembros de
tipos, tambin pueden contener metadatos. El cdigo de la aplicacin y los elementos de datos
Este cdigo define una sola clase (MiClaseConMiembrosObsoletos) con un solo procedimien
to de miembro (HaceAlgo), un procedimiento que evidentemente realiza alguna tarea. El pro
cedimiento se marca con el atributo ObsoleteAttribute. Por costumbre, todos los nombres
de atributos terminan con la palabra Attribute. Puede quitar esta parte de la palabra, si lo desea,
siempre y cuando la palabra resultante no entre en conflicto con ninguna palabra clave del len
guaje Visual Basic:
Class MiClaseConMiembrosObsoletos
<Obsolete> Sub HaceAlgo()
End Sub
End Class
Casi todos los atributos estn diseados con un propsito especfico en mente. Algunos atributos
instruyen a Visual Studio para que despliegue los miembros de una clase de maneras especficas.
Tal vez ya haya jugado con las caractersticas de edicin de formularios de Visual Studio para
disear una aplicacin simple de escritorio de Windows. Cuando agrega un control (como un
botn o un cuadro de lista) a un formulario y selecciona ese control, Visual Studio le permite
editar detalles de ese control mediante el rea del panel Propiedades (vase la figura 1-4).
El control Button est implementado como una clase, y muchos de sus miembros de clase apa
recen en el panel Propiedades, pero no todos ellos. Cuando se dise la clase Button, se agrega
ron atributos a sus miembros para indicarle a Visual Studio cules miembros deben aparecer en
el panel Propiedades y cules no. De manera obediente, Visual Studio examina estos atributos y
slo despliega las propiedades solicitadas.
Definicin de la versin
Como las suyas, mis aplicaciones son perfectas desde su lanzamiento inicial, y nunca tengo una
razn para modificarlas o agregar caractersticas. Pero hay organizaciones de desarrollo de software
(incluida una empresa grande a la que har referencia por su letra inicial M, para evitarle la pena)
que sienten la necesidad de estar por encima de sus competidores con versiones mejoradas de
sus ofrecimientos de software. Digamos que M tiene un procesador de palabras popular que
incluye la versin 1.0 de un componente de revisin ortogrfica. M tambin vende una herra
mienta de correo electrnico que depende especficamente de la versin 1.0 de ese mismo com
ponente compartido. Si, en una muestra de machismo competitivo, M lanza una actualizacin
del procesador de palabras y del componente de revisin ortogrfica (ahora la versin 2.0), qu
sucede a la capacidad de revisin ortogrfica de la herramienta de correo electrnico?
(d)
Figura 1-5. El proceso de desarrollo real de Visual Basic.
* Datamation 29 (7): julio de 1983, pp. 263-265. Tambin encontr el texto del artculo en Internet al hacer una bsqueda
con el ttulo. Una versin similar del texto, con unos cuantos cambios editoriales, tambin se encuentra bajo el ttulo Real
Programmers Dont Write Pascal (Los programadores reales no escriben en Pascal).
posible de personas a disfrutar las alegras de programar en .NET, de modo que ofrece la
Express Edition sin costo alguno. Esta edicin incluye una interfaz de usuario simplificada,
similar a la de Visual Studio, pero impone algunas restricciones a la capacidad de elaborar
programas. Aun puede editar directamente el cdigo fuente y crear aplicaciones de cualquier
complejidad, pero la interfaz de usuario no siempre le ayudar con esto. Por ejemplo, no
puede desarrollar aplicaciones Web con Visual Basic Express, a menos que instale el produc
to separado Visual Web Developer 2008. Adems, Express no incluye mucho soporte para
la implementacin; por lo general, se espera que las aplicaciones diseadas con la Express
Edition slo se usen en su propia estacin de trabajo.
Visual Studio 2008 Standard Edition
La edicin estndar de Visual Studio es como la Express Edition, con algunas adiciones,
como soporte a varios lenguajes, herramientas de desarrollo Web y soporte a implementa
cin mediante los mtodos ClickOnce y Windows Installer. Se incluye SQL Server 2005
Express Edition.
Visual Studio 2008 Professional Edition
ste es el nivel mnimo requerido por los programadores que desarrollarn aplicaciones
todos los das por dinero. Es la versin que uso e incluye todas las caractersticas avanzadas
que necesita un solo programador para desarrollo de aplicaciones para computadoras de
Resumen
Hace casi dos dcadas, Visual Basic transform el panorama del desarrollo en Windows con su
modelo de programacin de arrastrar y colocar, y su fastuosa estructura de desarrollo orientada a
eventos. Pero Windows ha cambiado mucho desde esos das de Windows 3.x. A medida que ha
cambiado, Visual Basic lo ha hecho junto con l. Visual Basic 2008, mediante su asociacin con
.NET Framework, proporciona acceso a las herramientas de programacin necesarias para desa
rrollar aplicaciones de calidad para los equipos de escritorio de Windows, Internet y la siguiente
generacin de dispositivos mviles.
Y Microsoft no est deteniendo este avance con la versin 2008. La siguiente versin de Visual
Basic, con los nombres de cdigo VBx y Hawaii, promete incluir caractersticas an ms avan
zadas. Esa versin estar construida sobre el motor de lenguaje dinmico (DLR, Dynamic Lan
guage Runtime) de Microsoft, permitindole interactuar libremente con bibliotecas de lenguajes
como Ruby y Python.
Proyecto | 23
Para usar el proyecto de ejemplo Cap01, seleccione la entrada Programacin en Visual Basic 2008
dentro del tipo de proyecto Visual Basic, y luego seleccione Cap01 Ejemplo del campo Plantillas
(vase la figura 1-10). Por ltimo, haga clic en Aceptar para crear el nuevo proyecto de ejemplo.
Una vez que el proyecto se carga, acceda al formulario principal del programa al hacer clic en el
archivo Form1.vb del Explorador de soluciones (vase la figura 1-11).
Esta presentacin predeterminada de la Visual Studio Professional Edition incluye tres compo
nentes de edicin: 1) el rea de edicin principal, donde aparece la vista de Form1; 2) el panel
Explorador de soluciones, que proporciona acceso a todos los archivos incluidos en el proyecto,
y 3) el panel Propiedades, que le permite editar varios aspectos del elemento seleccionado en el
rea del editor principal o cualquier otro lugar de la interfaz de usuario.
El proyecto de ejemplo es muy bsico. Incluye un formulario con un solo botn de accin. Al
hacer clic en este botn cuando se ejecuta la aplicacin, se despliega un mensaje simple. Ejecute
el proyecto al oprimir la tecla F5. Cuando aparece el formulario principal, al hacer clic en el
botn Vamos, haz clic en m!, se despliega el mensaje de la figura 1-12 (gol, dulce gol).
Entonces, qu hay con todo ese cdigo complejo que tuve que escribir para desarrollar esta
aplicacin de varias facetas? Todo est all, a la vista. En el panel Explorador de soluciones, haga
clic con el botn derecho en la entrada Form1.vb y seleccione Ver cdigo del men contextual.
(Al igual que con la mayora de los ejemplos de cdigo fuente presentados en este libro, he te
nido que ajustar ligeramente el texto para que se despliegue de manera apropiada en la pgina
impresa. Por lo general, esto incluye la divisin de una lnea lgica larga en dos o ms lneas
cortas.)
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
MsgBox("Hola, mundo!")
End Sub
End Class
Proyecto | 25
Y luego aqu
06 <System.Diagnostics.DebuggerNonUserCode(
)> _
07 Protected Overloads Overrides Sub Dispose _
(ByVal disposing As Boolean)
Estas lneas muestran atributos en accin. Estos dos atributos (DesignerGenerated y Debug-
gerNonUserCode) son un tanto parecidos al atributo Obsolete analizado antes, porque pro
porcionan cierta identidad de informacin al cdigo relacionado. DesignerGenerated modi
fica toda la seccin de cdigo de Form1, mientras que DebuggerNonUserCode slo modifica
al miembro Dispose. Para mayor claridad, ambos atributos incluyen sus rutas completas de
espacio de nombres. La palabra clave Global al principio del atributo DesignerGenerated es,
en realidad, una palabra clave de Visual Basic que indica Empieza en la parte ms elevada de la
jerarqua del espacio de nombres; sta no es una ruta relativa.
02 Partial Public Class Form1
Vio la palabra Partial en la lnea 02? S que la vio. Hey, espere un minuto; Public Class Form1
tambin apareci en el archivo Form1.vb, pero sin la palabra clave Partial. Visual Basic 2008
incluye una caracterstica que le permite dividir una sola clase (Form1 en este caso) entre varios
archivos de cdigo fuente al incluir la palabra clave Partial con una de sus partes, por lo me
nos. Estupendo, no? Permite a Visual Studio agregar cdigo de inicializacin complejo a su
formulario (como el que se encuentra en este archivo Form1.Designer.vb) sin preocuparse del
archivo de cdigo fuente (Form1.vb).
03 Inherits System.Windows.Forms.Form
La palabra clave Inherits define la relacin de herencia entre esta nueva clase Form1 y la clase
System.Windows.Forms.Form escrita antes. Form es la clase base y Form1 es la clase deri
vada; Form1 hereda toda la funcionalidad de la clase Form, incluido su aspecto inicial. En el
captulo 8 se analizarn con ms detalle estas relaciones entre clases.
44 Friend WithEvents Button1 As System.Windows.Forms.Button
Proyecto | 27
La palabra clave New crea nuevas instancias de clases. En este caso, esa nueva instancia est asig
nada al miembro de la clase Button1 definido en la lnea 44. En este momento, Button1 es una
instancia predeterminada de la clase Button; no tiene ninguno de sus valores personalizados,
como su tamao y posicin, o el texto de despliegue Vamos, haz clic en m! Todo esto se es
tablece de la lnea 27 a la 31:
27 Me.Button1.Location = New System.Drawing.Point(64, 104)
28 Me.Button1.Name = "Button1"
29 Me.Button1.Size = New System.Drawing.Size(152, 23)
30 Me.Button1.TabIndex = 0
31 Me.Button1.Text = "Vamos, haz clic en m!"
Esto agrega la instancia Button1 a la lista de Controls administrado por Form1. La palabra cla
ve Me usada en todo este cdigo alude a la propia clase Form1, de modo que Me.Button1 alude
al miembro de la clase Button1 que se encuentra especficamente en la clase Form1 actual.
La mayor parte del cdigo de este archivo aparece en el procedimiento del miembro Initia-
lizeComponent:
21 Private Sub InitializeComponent()
...
43 End Sub
Cuando Visual Basic crea una instancia de Form1 para desplegarlo en la pantalla, llama al pro
cedimiento InitializeComponent para hacer el trabajo de agregar los controles al formulario.
En realidad, Visual Basic llama al constructor del formulario, que, a su vez, llama a Initiali-
zeComponent. Los constructores son miembros de clase especiales que realizan cualquier ini
cializacin necesaria en la instancia de clase. Son llamadas automticamente por .NET cada vez
que se crea una instancia de clase. En Visual Basic, todos los constructores usan el nombre New,
como en el siguiente cdigo:
Friend Class ClassWithConstructor
Public Sub New()
' ----- Aqu va todo el cdigo de inicializacin.
End Sub
End Class
Proyecto | 29
Era una noche oscura y tormentosa. Hctor miraba cansado con sus ojos enrojecidos, a travs
de sus lentes con armazn negro, y a travs de la neblina de las luces fluorescentes de la pantalla
enriquecida con fsforo. En realidad haban pasado cuatro meses desde que empez el proyecto
de seis meses? En realidad su jefe haba amenazado con correrlo despus de ver sus avances?
Pareca como si todos esos programas de MS-DOS que haba escrito para la compaa durante
aos no significaran nada. Por qu prometi llevar el sistema interno de la compaa a Win-
dows? En un momento de desesperacin, las lgrimas resbalaron por sus mejillas, diluyendo su
ltima lata de Jolt Cola.
Son las 8:00 a.m. Un fuerte golpe en el escritorio de Hctor lo saca de pronto de su sueo,
mientras la saliva an resbala por la comisura de sus labios. Qu fue eso? Qu es esa caja en
su escritorio? V-i-s-u-a-l B-a-s-i-c? Una nota en la caja dice que reescriba su cdigo en esto.
Desesperado por probar lo que sea, Hctor instala los tres disquetes en su poderosa 386.
Seis semanas despus, Hctor ha completado el proyecto, adelantndose al calendario, con las
caractersticas completas y con los elogios de su jefe y su departamento. Y todo gracias a Visual
Basic. Pero VB no slo mejor su vida de programacin. En general, es ms feliz, ha abandonado
el hbito de la cafena, puede levantar 120 kilos, ya no cojea, ha aumentado su libido y tiene los
dientes ms blancos. Gracias, Visual Basic 1.0!
30
Usted podra escribir esta lgica de muchas maneras; ste es slo un ejemplo. Ahora debe con-
vertir este seudocdigo en su lenguaje preferido; en este caso, Visual Basic (no se preocupe por
ahora por los detalles de la sintaxis):
01 textoOriginal = InputBox("Ingrese el texto que se invertir.")
02 If (Len(textoOriginal) = 0) Then Return
03 textoFinal = ""
04 Do While (textoOriginal <> "")
05 unCaracter = Right(textoOriginal, 1)
06 textoFinal &= unCaracter
07 textoOriginal = Left(textoOriginal, _
Len(textoOriginal) - 1)
08 Loop
09 MsgBox("El texto invertido es: " & textoFinal)
Adems de las funciones, Visual Basic tambin incluye procedimientos. Los procedimientos
empaquetan cdigo previamente escrito en un paquete con nombre, como las funciones,
pero no devuelven un valor. Deben usarse como instrucciones independientes; no puede
usarlas donde usara una variable o una llamada a funcin. La llamada a MsgBox en la lnea
09 es un ejemplo tpico de una llamada a procedimiento en uso. (MsgBox es en realidad una
funcin, pero en este cdigo est enmascarado como un procedimiento; se analizar con
ms detalle en pginas posteriores.)
El cdigo de ejemplo anterior podra ser un poco ms eficiente. En realidad, es posible que Mi-
crosoft obtuviera un borrador inicial de este libro, porque incluy una caracterstica de inversin
de caracteres en Visual Basic, y la llam StrReverse:
textoOriginal = InputBox("Ingrese el texto que se invertir.")
If (Len(textoOriginal) = 0) Then Return
textoFinal = StrReverse(textoOriginal)
MsgBox("El texto invertido es: " & textoFinal)
Muy bien; Visual Basic ya incluye una caracterstica de inversin de caracteres, parte de ese
cdigo de biblioteca previamente escrito del que sigo hablando. Visual Basic incluye muchas
funciones intrnsecas que se consideran parte del lenguaje y que empaquetan mucha funcionali-
dad til ya escrita. Muchas de estas funciones aparecen en el espacio de nombres Microsoft.
VisualBasic, que queda automticamente disponible para su cdigo fuente de Visual Basic
cuando crea un nuevo proyecto de VB.
Todos los datos administrados por el CLR estn almacenados en la memoria de la computadora,
y cada valor de datos est separado y protegido de los dems. Es como si cada valor de datos
tuviera su propia taza individual, como se muestra en la figura 2-1.
Todos los valores de datos administrados por el CLR tienen contenido y tipo. El contenido son los
datos reales: la cadena de texto abc, el nmero 5, una factura, t negro, de naranja. Cualquier
cosa que ponga en la taza, se es el contenido. En algunos casos, .NET no permite almacenar
algo en la taza (los tipos de referencia se analizarn en breve y los tipos de valor nulos se des-
cribirn en el captulo 6).
Los tipos indican la clase de contenido almacenado en la taza. Esto se muestra en la figura 2-1
con la forma de cada taza. Cada una de ellas tiene lmites en el tipo de datos que puede verterse
en ella: una cadena de texto, un nmero entero o una factura para el cliente.
Literales
Algunos valores bsicos de datos, como nmeros y cadenas de texto, pueden ingresarse en su
cdigo fuente y usarse tal como estn. Por ejemplo, el procedimiento MsgBox despliega una
ventana con un mensaje de texto. La instruccin
MsgBox("La respuesta es " & 42)
incluye una cadena literal, La respuesta es y un valor entero literal, 42. (El smbolo & es un
operador que une los dos valores en una nueva cadena.) Las literales se usan una vez y desapare-
cen. Si quiere mostrar el mismo mensaje La respuesta es 42 de nuevo, tendr que escribir una
vez ms los mismos valores de literal en una parte diferente del cdigo fuente.
Visual Basic da soporte a varios tipos de literales bsicas. Las literales de cadena estn siempre
entre comillas. Si quiere incluir una comilla en medio de una cadena, debe incluir dos comillas
en lugar de una:
"Esto es ""literalmente"" un ejemplo."
Las literales de cadena pueden ser realmente largas, hasta de dos mil millones de caracteres de
longitud; si escribiera un carcter por segundo, le tomara 63 aos alcanzar la longitud mxima
de la cadena. Visual Basic tambin incluye una literal de carcter que es exactamente de un ca-
Variables
Todos los valores de datos literales son buenos y malos, pero slo resultan tiles una vez y se van.
Cada vez que quiera usar un valor de literal, debe volver a escribirlo. Es como si los valores de
datos estuvieran almacenados en tazas desechables, en lugar de que sean de fina porcelana china.
La variable respuesta se asigna dos veces con dos cadenas diferentes: una A (lnea 01) y luego
AA (lnea 07). Conserva cualquier valor que se le haya asignado al final; ambas lneas 03 y 05
despliegan A en una ventana de cuadro de mensaje. Y no tiene que asignar slo cadenas de
literal; es posible asignar a respuesta el resultado de cualquier cosa que genere una cadena. La
lnea 07 usa una funcin integrada Visual Basic, StrDup, para devolver la cadena de dos carac-
teres AA y asignarla a respuesta.
El uso de variables es un proceso de dos pasos. En primer lugar, debe declarar la variable y luego
debe asignarle un valor. La instruccin Dim se ocupa de la parte de la declaracin; le permite
indicar el nombre y el tipo de una variable. Su sintaxis bsica es muy sencilla:
Dim respuesta As String
Una sola variable puede tener nuevos valores asignados una y otra vez. Para esas ocasiones en
que quiere que su variable tenga un valor especfico inmediatamente despus de la declaracin,
puede combinar una declaracin y una asignacin en una sola instruccin:
Dim respuesta As String = "La respuesta"
Por supuesto, no est limitado a una sola declaracin; puede crear todas las variables que necesite
en su cdigo. Cada una suele usar su propia instruccin Dim:
Dim pregunta As String
Dim respuesta As String
Tambin puede combinarlas en una sola instruccin, aunque creo que es horrible:
Dim pregunta As String, respuesta As String
Lo ve, le dije que era horrible. Esto es slo el principio de lo que es posible con la instruccin
Dim. Entrar en ms detalles a medida que avance el captulo.
Tipos de datos
El tipo de datos String es til, pero slo representa una de las formas de taza que estn a su dis-
posicin. .NET Framework define varios tipos de datos centrales. Cada tipo se implementa como
una clase especfica dentro del espacio de nombres System. El tipo de datos ms bsico, una taza
grande que puede contener cualquier tipo de datos, es denominado Object. Ms que nada, se
trata de un objeto con O mayscula. En la jerarqua del espacio de nombres de la biblioteca de
clases de .NET, se localiza en System.Object. Es la madre de todas las clases en .NET; todas las
dems clases, estructuras, enumeraciones y delegados, sin importar su posicin en la jerarqua
de espacio de nombres, sean escritas por Microsoft o por usted, derivan de System.Object. No
hay vuelta de hoja; no puede crear un tipo que derive de algo diferente.
As que regrese a estos tipos de datos centrales sobre los que he estado hablando. Coinciden
con los cuatro tipos de valores de datos de literal que enumer antes: valores de cadena, fecha,
nmero y booleanos. En la tabla 2-1 se presenta una lista de estos tipos de datos centrales. Cada
tipo tambin tiene un nombre especfico de Visual Basic que puede (y debe) usar en cambio.
Los desarrolladores de Microsoft a cargo de los tipos de datos de Visual Basic tuvieron suerte en
ese trabajo porque todos los tipos de datos centrales de Visual Basic son simples envolturas para
tipos de datos especficos implementados por .NET. Los nombres de Visual Basic dados para cada uno
de estos tipos de datos centrales son completamente intercambiables con los nombres de .NET.
Por ejemplo, Integer es equivalente por completo a System.Int32. En realidad, cuando escribe
cdigo de Visual Basic, es mejor usar sinnimos de Visual Basic, porque la mayora de los desarro-
lladores de Visual Basic esperan estos nombres de tipos de datos en el cdigo que leen y escriben.
Excepto por Object y String, todos estos tipos de datos son tipos de valor. Todos los tipos de
valor se derivan de System.ValueType (que, a su vez, deriva de System.Object).
Los tipos de datos SByte, UInteger, ULong y UShort se agregaron a Visual Basic con su versin
2005, aunque sus equivalentes del espacio de nombres System han estado en .NET desde sus
inicios. A diferencia de los dems tipos de datos centrales, estos cuatro tipos no son compatibles
con CLS; es decir, no pueden usarse para interactuar con componentes de .NET y lenguajes
que se reducen a las caractersticas esenciales necesarias de .NET. Por lo general, esto no suele ser
una limitacin, pero est prevenido cuando trabaje con componentes o lenguajes de terceros.
Declaracin avanzada
Cuando mencion la necesidad de declarar y asignar variables, realmente me estaba concen-
trando en los tipos de valor. Los tipos de referencia requieren un paso adicional: la creacin de
instancias. Considere las siguientes instrucciones de declaracin:
Estas lneas declaran tres variables separadas: dos tipos de valor (Integer) y un tipo de referencia
(Object). Aunque slo una variable tiene una asignacin explcita de datos, los tres tienen en
realidad asignado algo, explcita o implcitamente. Veamos de nuevo estas instrucciones y revise-
mos lo que en realidad est asignado a cada variable.
Dim valorPredeterminado As Integer = 0
Dim valorNoPredeterminado As Integer = 5
Dim referenciaPredeterminada As Object = Nothing
Ya ocurrieron la declaracin y la asignacin para todas las variables, al usar la instruccin Dim.
La variable valorPredeterminado, con su asignacin predeterminada de 0, puede usarse de
inmediato en ecuaciones. Sin embargo, la variable de tipo de referencia referenciaPredeter-
minada es slo una taza vaca, sin datos predeterminados que manipular. Son caractersticas de
Visual Basic que le permiten comparar un tipo de referencia con Nothing, y podra hacer esto
de inmediato, pero en realidad no son datos. Y recuerde que las variables viven para administrar
datos.
Los valores de datos de referencia necesitan la creacin de instancias, y sta requiere la palabra
clave New:
Dim referenciaPredeterminada As Object = New Object
Ahora referenciaPredeterminada seala a un objeto real; y ya que esta taza tiene algo con-
sumible dentro, aunque slo sea algo de System.Object, no queda mucho por saborear. Las
cadenas son un poco ms interesantes y tambin tienen constructores ms interesantes.
Como recordar del captulo 1, un constructor es un bloque de cdigo de inicializacin que
se ejecuta cuando crea un nuevo valor de datos o un objeto. Algunos objetos le permiten pro-
porcionar informacin adicional que se usa en el proceso de inicializacin. Un constructor pre-
determinado no le permite proporcionar ninguna informacin adicional; slo funciona por su
cuenta, inicializando datos como si no fuera el trabajo de nadie. Hay un lmite en el nmero de
constructores en una clase, pero a cada uno debe pasrsele un tipo diferente de informacin.
As que regresemos a las cadenas. El constructor predeterminado para una cadena simplemente
crea una cadena en blanco, de longitud cero:
Dim cadenaMasAbuirridaDelMundo As String = New String
Esto es porque Visual Basic trata de manera especial a las cadenas. Las literales de cadena en
realidad son instancias de los valores de datos String; es como si creara una nueva instancia
de String empleando la clase System.String. Por lo menos, eso es cierto cuando se usa el
constructor predeterminado del tipo de datos String. Pero String tambin tiene constructores
interesantes. (Entrar en los detalles de los constructores en el captulo 8.) Uno de los construc-
Si va a usar el mismo tipo de datos despus de la palabra clave As que utiliza despus de la pala-
bra clave New, puede usar una sintaxis reducida:
Dim mmBueno As New String("M"c, 25)
Al igual que con los tipos de valor, tambin puede dividir la instruccin en instrucciones de
declaracin y asignacin:
Dim mmBueno As String
mmBueno = New String("M"c, 25)
Constantes
Las literales no cambian, pero puede usarlas slo una vez en su cdigo. Las constantes son
una cruza entre una literal y una variable; tienen un solo valor que nunca cambia, como las
literales de datos, pero tambin tienen un nombre que puede usar una y otra vez, como las va
riables.
Las constantes se declaran empleando la palabra clave Const en lugar de Dim:
Const VelocidadDeLaLuz As Integer = 300000
La asignacin real del valor a la constante ocurre en la propia instruccin, con el valor despus
del operador =. Una vez que se declara y asigna su constante, est disponible para usarla en ins-
trucciones reales de su cdigo real:
MsgBox("La velocidad de la luz en kilmetros/segundo: " & VelocidadDeLaLuz)
Hay cinco modificadores de acceso. En el captulo 6 hablar ms acerca de ellos y de los campos
en general.
Intermedio
Ya fue demasiado. Hacerse una idea acerca de datos y variables es probablemente la parte ms
compleja de la programacin en Visual Basic. Una vez que tenga los datos en las variables, ser
muy fcil manipularlos.
Aunque la idea de una taza de t puede hacer que salga de la habitacin como un luntico de-
lirante, tal vez quiera darse unos minutos, tomar una copa, un vaso, un plato o un tarro de su
bebida preferida y relajarse. Lo ver en 20 o 30 minutos.
Comentarios
Si usted es un fantico de la pera, sabe lo excitante que puede ser una buena pera, sobre todo
un trabajo clsico presentado con el libreto original en idioma extranjero. Si no lo es, sabe lo irri-
tante que puede ser escuchar varias horas de un libreto en idioma extranjero. Con el advenimien-
to de los subttulos que describen el contenido en el idioma del espectador, quienes hasta ahora
han extrado poca alegra de la experiencia de la pera an la encontrarn repulsiva, slo que esta
vez en su lengua nativa. Pero por lo menos ahora sabrn por qu no disfrutan la historia.
Eso es realmente lo que hacen los comentarios: le indican en su propio idioma lo que en realidad
est pasando en un idioma extranjero. En este libro, el idioma extranjero es Visual Basic, y el
espaol es el habla comn. Tal vez resulte que un bloque determinado de cdigo de Visual Basic
est mal escrito o incluso sea detestable, pero si los comentarios que lo acompaan son exactos,
puede resultar molesto en su propio idioma, mientras comprende el proceso en un idioma com-
prensible para los seres humanos.
Por lo general, los comentarios aparecen en lneas individuales, pero tambin puede adjuntar un
comentario al final de una lnea de cdigo existente. Si una lnea lgica est dividida en varias
lneas fsicas usando el carcter de continuacin de lnea _, un comentario final slo es vlido
al final de la lnea fsica:
' ----- ste es un comentario independiente, en una lnea individual.
Dim contador As Integer ' ste es un comentario al final.
MsgBox("El contador empieza en " & _ ' COMENTARIO NO VLIDO!
contador) ' Pero ste s es vlido.
Los comentarios tambin empiezan con la palabra clave REM (de REMark, comentario), pero
la mayora de los programadores usan, en cambio, la variacin de una sola comilla.
Instrucciones Option
En unos ejemplos de cdigo anteriores vio que Visual Basic proporcionara una asignacin pre-
determinada a una variable (por lo menos para tipos de valor) si no inclua una. En ciertos casos,
Visual Basic tambin proporcionar la declaracin si la deja fuera. En la instruccin:
valorNuevo = 5
si no hay una instruccin Dim que defina valorNuevo, Visual Basic declarar la variable en
su nombre, asignndole el tipo de datos Object. No deje que esto suceda! No sabe qu tipo de
problema tendr si permite estas prcticas en su cdigo. Rpidamente encontrar su cdigo
lleno de misteriosos errores de lgica, problemas esotricos con los datos, piojos recurrentes,
etctera.
El problema es que Visual Basic no se quejar si escribe mal el nombre de su variable autodecla-
rada. Si se deja sin revisar, tales prcticas podran llevar a un cdigo como ste:
valorNuevo = 5
MsgBox(valorNeuvo)
Vea ese error de escritura en la segunda lnea. Qu? Visual Basic compilaba sin errores? Y
ahora su cuadro de mensaje despliega nada, en lugar de 5? Podra evitar ese trauma mediante
el uso juicioso de las instrucciones Option incluidas en el lenguaje Visual Basic. Hay cuatro de
esas instrucciones:
Option Explicit On
Esta instruccin le obliga a declarar todas las variables usando Dim (o una instruccin si-
milar) antes de usarla. Es posible reemplazar On con Off en la instruccin, pero no lo
haga.
Option Strict On
Visual Basic har algunas conversiones simples de datos cuando las necesite. Por ejemplo,
si asigna un valor de datos Long de 64 bits a una variable Integer de 32 bits, Visual Basic
convertir normalmente esos datos a un tamao ms pequeo, quejndose slo si los datos
no corresponden. Este tipo de conversin (una conversin de estrechamiento) no siempre
es seguro porque en ocasiones los datos de origen fallarn al acomodarse al destino. (Una
conversin de ensanchamiento, como cuando se almacenan datos Integer en Long, siempre
funciona, porque el destino siempre puede contener el valor de origen.) La instruccin
Instrucciones Option | 45
O, para ahorrar precioso espacio en disco, establezca los valores predeterminados que se aplicarn
a todo su proyecto a travs de las propiedades de ste. En Visual Studio, seleccione el comando
de men Proyecto Propiedades. En la ventana de propiedades del proyecto que aparece, se-
leccione la ficha Compilar, y establezca sus opciones para los campos Option explicit, Option
strict, Option compare y Option infer (vase la figura 2-2).
se vuelve:
siete = 7
antes de la aplicacin final del operador de asignacin (=). Un operador unario aparece a la dere-
cha de su operando. Por ejemplo, el operador de negacin unario convierte un nmero positivo
en uno negativo:
sieteNegativo = 7
Operador Descripcin
+ El operador de suma adiciona dos nmeros.
+ El operador unario de ms retiene el signo del valor numrico. No es muy til hasta que sobrecarga el operador, algo
que se aborda en el captulo 12.
El operador de resta sustrae el segundo operando del primero.
El operador unario de negacin invierte el signo de su operando numrico asociado.
Operadores bsicos | 47
Operador Descripcin
* El operador de multiplicacin multiplica dos valores numricos.
/ El operador de divisin divide el primer operando numrico entre el segundo, regresando el cociente, incluido cual-
quier sobrante decimal.
\ El operador de divisin entero divide el primer operando numrico entre el segundo, regresando el cociente, pero con
el sobrante decimal truncado.
Mod El operador mdulo divide el primer operando numrico entre el segundo, y slo devuelve el sobrante como un valor
entero.
^ El operador exponencial eleva el primer operando (la base) a la potencia del segundo (el exponente).
& El operador de unin de cadenas une dos operandos de cadena y devuelve una nueva cadena con los resultados
combinados.
Anda El operador de conjuncin devuelve True si ambos operandos booleanos tambin son True.
AndAlso Este operador es como And, pero no examina ni procesa el segundo operando si el primero es False.
Or a
Este operador de disyuncin devuelve True si cualquiera de los operandos tambin es True.
OrElse Este operador es como Or, pero no examina ni procesa el segundo operando si el primero es True.
Nota El operador de negacin devuelve el opuesto de un operando booleano.
Xor a
El operador or excluyente devuelve True si exactamente uno de los operandos tambin es True.
<< El operador de desplazamiento a la izquierda desplaza los bits individuales de un operando entero que se encuentra a
la izquierda en el nmero de posiciones de bits en el segundo operando.
>> El operador de desplazamiento a la derecha desplaza los bits individuales de un operando entero que se encuentra a
la derecha en el nmero de posiciones de bits en el segundo operando.
= El operador de comparacin igual a devuelve True si los operandos son iguales entre s.
< El operador de comparacin menor que devuelve True si el primer operando es menor que el segundo.
<= El operador de comparacin menor que o igual a devuelve True si el primer operando es menor que o igual a el
segundo.
> El operador de comparacin mayor que devuelve True si el primer operando es mayor que el segundo.
>= El operador de comparacin mayor que o igual a devuelve True si el primer operando es mayor que o igual a el
segundo.
<> El operador de comparacin no es igual a devuelve True si el primer operando no es igual a el segundo.
Like El operador de comparacin de patrn devuelve True si el primer operando coincide con un patrn de cadena
especificado por el segundo operando.
Is El operador de comparacin de objetos igual a devuelve True si ambos operandos realmente representan la misma
instancia de un valor de datos en la memoria. El establecimiento del segundo operando en Nothing le permite
probar una referencia a variable para ver si contiene datos.
IsNot El operador de comparacin de objetos no es igual a es el opuesto al operador Is.
a
Los operadores And, Or, Not y Xor tambin funcionan como operadores en el nivel de bits. En el captulo 6 me referir a eso en Operadores.
En esta instruccin, el segundo operando del operador de multiplicacin * es otra expresin, que
incluye su propio operador.
Cada subrutina define el tipo de datos y el orden de los argumentos que pasa. Esta lista de argu-
mentos puede incluir uno o ms argumentos opcionales, que son valores predeterminados asigna-
dos si no los incluye. Una subrutina tambin podra sobrecargarse, definiendo diferentes listas de
argumentos posibles con base en el nmero y tipo de datos de los argumentos. Encontraremos
gran cantidad de stos ms adelante.
Las funciones son un poco ms interesantes porque devuelven un valor til. A menudo, este
valor se asigna a una variable:
Dim saldoVencido As Boolean
saldoVencido = TieneSaldoExcepcional(idCliente)
Entonces puede hacer algo con este resultado. Si quiere, puede ignorar el valor que devuelve
una funcin, y ya lo hicimos. La funcin MsgBox usada antes devuelve la identidad del botn
en pantalla en que el usuario hizo clic para cerrar el cuadro de mensaje. Si slo incluye un
botn Aceptar (la opcin predeterminada), tal vez no le preocupe en qu botn haga clic el
usuario.
MsgBox("Vamos, haz clic en el botn Aceptar.")
Condiciones
En ocasiones tiene que hacer alguna eleccin, y las expresiones condicionales le ayudarn a to-
marlas. Visual Basic incluye soporte para condiciones, que usan pruebas de datos para determinar
cul cdigo debe procesarse a continuacin.
La condicin original siempre sigue a la palabra clave If. Si esa condicin falla, puede especifi-
car condiciones adicionales despus de una palabra clave ElseIf, como en la lnea 04. Puede
incluir todas las clusulas ElseIf que necesite. La condicin opcional Else no le permite
especificar una expresin de prueba. En cambio, compara todo lo que an no se captura con
las clusulas If o ElseIf. Slo una clusula Else se permite por instruccin If.
Ramas
La palabra clave Then de cada condicin es seguida por una o ms instrucciones de Visual
Basic que son procesadas si la condicin asociada se evala como True. Todas las instruccio-
nes, hasta la siguiente Else, ElseIf o End If, se incluyen en el bloque de instrucciones de
esa rama. Puede incluir cualquier cantidad de instrucciones en un bloque de rama, incluidas
instrucciones If subordinadas. En el cdigo de ejemplo, las lneas de rama 02 y 03 se pro-
cesan si la condicin original tuveUnMartillo es verdadera. En cambio, se procesa la lnea
05 si la condicin original falla, pero pasa la segunda condicin tuveUnaPala. Si ninguna
de las condiciones es True, se ejecuta la rama de Else, en la lnea 07.
Condiciones | 51
En el caso de condiciones con ramas de una sola instruccin y sin clusulas ElseIf, una
opcin de una sola lnea puede mantener su cdigo con aspecto limpio.
If (GuardarDatos() = True) Then MsgBox("Datos guardados.")
If (HoraDelDia >= #13:00#) _
Then estadoActual = EstadoTrabajo.IrACasa _
Else estadoActual = EstadoTrabajo.OcupadoTrabajando
Las instrucciones If son estupendas porque hacen que su cdigo sea un poco ms que un con-
junto aburrido de instrucciones lineales paso a paso que nunca se desvan por ninguna razn. El
software se escribe para dar soporte a algn proceso real, y los procesos reales muy pocas veces
son lineales. La instruccin If permite que su cdigo reaccione a diferentes condiciones de da-
tos, tomando la rama apropiada cuando es necesario.
Una vez que todo el bloque If...End If se completa, el procesamiento contina con la si-
guiente instruccin que sigue a End If.
Y as, a travs de muchas clusulas ElseIf ms. Es efectivo, pero un poco tedioso, porque su
cdigo debe probar cada caso de manera especfica. La instruccin Select Case proporciona
una opcin ms limpia para valores de comparacin simples contra una lista:
01 Select Case valorBillete
02 Case 1
A diferencia de la instruccin If, que revisa un resultado booleano, Select Case compara un
solo valor contra un conjunto de valores de caso de prueba. En el ejemplo, la variable valor-
Billete se compara contra los diferentes valores identificados por cada clusula Case. Todo el
cdigo que sigue a una clusula Case (hasta la siguiente clusula Case) es la rama que se procesa
cuando se encuentra una coincidencia. Una condicin opcional Case Else (lnea 16) captura
cualquier cosa que no coincide con ningn otro Case. Por lo general, las clusulas Case presen-
tan listas de valores individuales para comparacin. Tambin pueden incluir una lista de valores
de comparacin separados por comas (lnea 12), o expresiones de comparacin de rango simple
(lnea 14).
Funciones IIf e If
Visual Basic incluye dos variaciones de la instruccin If para uso en lnea. Considere la si-
guiente instruccin:
If (genero = "F") Then generoCompleto = "Femenino" _
Else generoCompleto = "Masculino"
Empleando la funcin IIf, esta instruccin se comprime en una sola instruccin de asignacin
con una condicin incrustada:
generoCompleto = IIf(genero = "F", "Femenino", "Masculino")
La funcin IIf tiene tres argumentos delimitados por comas. El primero es la condicin, que
debe dar como resultado un valor booleano True o False. El segundo argumento es devuelto
por la funcin si la condicin es True; un resultado de condicin False devuelve el tercer ar-
gumento. En el caso de condiciones simples que estn destinadas a regresar valores nicos a una
variable comn, es realmente una funcin til. Pero como con cualquier cosa realmente til, deben
tomarse precauciones. La advertencia con IIf es que se procesar cualquier cosa que aparezca den-
tro de la instruccin IIf, aunque no se devuelva como resultado. He aqu un ejemplo peligroso:
resultadoPurga = IIf(nivel = 1, ConjuntoPurga1(
), ConjuntoPurga2(
))
Condiciones | 53
En esta versin del operador If, si el primer argumento se evala como Nothing, el operador
devuelve el segundo argumento. Si el primero no es Nothing (es decir, si en realidad tiene algo),
el operador devuelve, en cambio, el primer argumento. El objetivo es devolver algo que no sea
Nothing, aunque se trate de una doble negacin.
Bucles
Visual Basic incluye tres tipos principales de bucles: For...Next, For Each...Next y Do...
Loop. Al igual que las condiciones le permiten dividir la monotona secuencial de su cdigo
mediante ramas, los bucles agregan algo a la utilidad de su cdigo al dejar que repita un bloque
especfico de lgica un nmero fijo o variable de veces.
Este ejemplo se repite 12 veces (1 To 12), una vez para cada mes. Puede especificar cualquier
valor de inicio y final que desee; este rango tambin puede especificarse utilizando variables o
funciones que devuelven valores numricos. Una vez que se obtienen los valores iniciales y fina-
les, vuelven a calcularse cada vez a travs del bucle, aunque se use una llamada a funcin para
obtener uno o ambos lmites.
Por lo general, el bucle aumenta en uno (1) cada vez. Puede modificar este comportamiento
predeterminado al adjuntar una clusula Step al final de la lnea de la instruccin For:
For cuentaHaciaAbajo = 60 To 0 Step -1
...
Next cuentaHaciaAbajo
Una variante adicional a la sintaxis le permite declarar la variable del contador del bucle dentro
de la propia instruccin. Estas variables slo estn disponibles dentro del bucle y dejan de existir
una vez que se sale del bucle.
For cualMes As Integer = 1 To 12
procesarDatosMensualmente(cualMes)
Next cualMes
Bucles Do . . . Loop
En ocasiones querr repetir un bloque de cdigo, siempre y cuando cierta condicin sea verdade-
ra, o slo hasta que lo sea. La estructura Do...Loop realiza ambas tareas. La instruccin incluye
una clusula While o Until que especifica las condiciones para el procesamiento continuo del
bucle. Por ejemplo, la siguiente instruccin hace algo de procesamiento para un conjunto de
fechas, de una inicial a una final:
Dim fechaProceso As Date = #1/1/2000#
Do While (fechaProceso < #2/1/2000#)
' ----- Realizar procesamiento para la fecha actual.
ProcesarContenido(fechaProceso)
Bucles | 55
Puede hacer que la condicin incluida sea tan simple o compleja como lo desee. Al poner la
clusula Until o While en la parte inferior del bucle garantiza que las instrucciones dentro del
bucle siempre se procesen, aunque sea una vez:
Do
...
Loop Until (fechaProceso >= #2/1/2000#)
Si la condicin del bucle nunca se cumple, ste continuar eternamente. Por tanto, si quiere que
se salga de un bucle en alguna parte (y por lo general lo hace), asegrese de que la condicin se
pueda cumplir en algn momento.
Hay otro bucle similar a Do...Loop, llamado While...End While. Sin embargo, slo existe
para compatibilidad con versiones anteriores. Use, en cambio, la instruccin Do...Loop.
Instrucciones de salida
Por lo general, cuando ingresa en un bucle, tiene todas las intenciones de recorrerlo por com-
pleto el nmero de veces especificado en las condiciones iniciales. En el caso de los bucles For,
espera seguir durante todo el rango numrico o la coleccin de elementos. En los bucles Do,
planea mantener el bucle ejecutndose mientras la condicin de salida no se cumpla. Pero puede
haber bucles de los que desee salir antes. Logra esto empleando la instruccin Exit.
Hay dos instrucciones Exit especficas de bucles:
Exit For
Sale de un bucle For...Next o For Each...Next de inmediato
Exit Do
Sale de una instruccin Do...Loop de inmediato
Cada instruccin Exit sale del bucle que contiene la instruccin; el procesamiento contina en
la lnea que sigue de inmediato al bucle:
For cualMes = 1 To 12
If (procesarDatosMensualmente(cualMes) = False) Then Exit For
Next cualMes
' ----- El cdigo sigue aqu sin importar cmo se salga del bucle.
El cdigo de ejemplo est diseado para recorrer en bucle los 12 meses. Sin embargo, una falla
en el procesamiento en cualquiera de los 12 meses har que se salga de inmediato del bucle,
abandonando todas las acciones de procesamiento de los meses restantes. La instruccin Exit
Do hace que se salga de inmediato del bucle Do...Loop de manera similar.
Instrucciones Continue
Debido a que cuando se sale de un bucle se abandonan todos los pasos restantes del bucle, podra
omitirse un procesamiento importante que se hubiera dado en pasos posteriores. Visual Basic
incluye una instruccin Continue que le permite abandonar slo el paso actual del bucle.
Hay diferentes variaciones de las instrucciones Continue para cada tipo de bucle:
Continue For
Salta de inmediato al final del bucle For...Next o For Each...Next y prepara para el
siguiente paso. La variable del bucle se aumenta y se compara con el rango o los lmites de
la coleccin.
Continue Do
Salta de inmediato al final de la instruccin Do...Loop y prepara el siguiente paso. Se vuel-
ve a evaluar la condicin Until o While.
Debido a que las condiciones de bucle se vuelven a evaluar cuando se usan las instrucciones
Continue, hay ocasiones en que Continue puede causar la salida del bucle, cuando ya se ha
hecho el paso final por el bucle.
En este ejemplo, la instruccin Continue For omite el procesamiento de meses que no tienen
datos para procesarse:
For cualMes = 1 To 12
If (DatosDisponibles(cualMes) = False) Then Continue For
RecuperarDatos(cualMes)
ProcesarDatos(cualMes)
GuardarDatos(cualMes)
Next cualMes
En casi todos los casos, si est interesado en modificar el valor de un parmetro y hacer que los
cambios regresen al llamador, use ByRef; de otra manera, use ByVal.
De la lnea 02 a la 08 del cdigo de ejemplo se encuentra el cuerpo del procedimiento, donde
aparece toda su lgica. Cualquier variable que se usar exclusivamente en la rutina tambin se
define aqu, al igual que en la variable elMensaje de la lnea 02. La subrutina siempre concluye
con una instruccin End Sub.
Funciones
La sintaxis de una funcin slo difiere ligeramente de la usada en las subrutinas, para dar soporte
a un valor que se devuelve.
01 Function EsPrimo(ByVal origen As Long) As booleano
02 ' ----- Determina si el origen es un nmero primo.
03 Dim pruebaValor As Long
04 If (origen < 2) Then
05 Return False
06 ElseIf (origen > 2) Then
07 For pruebaValor = 2 To origen \ 2&
08 If ((origen Mod pruebaValor) = 0) Then
09 Return False
10 End If
11 Next pruebaValor
12 End If
13 Return True
14 End Function
Al igual que con las subrutinas, la lnea de declaracin de la funcin aparece primero (lnea 01),
seguida por el cuerpo (de la lnea 02 a la 13) y la instruccin de cierre End Function (lnea 14).
La lnea de declaracin incluye una definicin adicional de tipo de datos despus de la lista de
parmetros. ste es el tipo de datos del valor final que habr de regresarse al cdigo que llama.
Use este valor de resultado en el cdigo de llamada como lo hara con cualquier otro valor o
variable. Por ejemplo, la siguiente lnea llama a la funcin EsPrimo y almacena su resultado
booleano en una variable:
resultadoPrimo = EsPrimo(23)
Para indicar el valor que se regresar, use la instruccin Return (que se describe ms adelante
en el captulo). El cdigo de ejemplo hace eso en las lneas 05, 09 y 13. (Una sintaxis antigua
Propiedades
Un poco antes mencion los campos, que son variables o constantes que aparecen dentro de una
clase, pero fuera de cualquier definicin de procedimiento.
01 Class RangoPorcentaje
02 Public Porcentaje As Integer
03 End Class
Las propiedades son similares a los campos; se usan como variables o constantes en el nivel de la
clase. Pero estn programadas como las funciones, aceptan parmetros, tienen valores de resulta-
do e incluyen toda la lgica que necesite.
Las propiedades suelen usarse para proteger datos de una clase privada con lgica que deja fuera
valores no apropiados. La siguiente clase define una sola propiedad de acceso que proporciona
acceso a los campos relacionados ocultos:
01 Class RangoPorcentaje
02 ' ----- Almacena un porcentaje que slo va de 0 a 100.
03 Private porcentajeGuardado As Integer
04 Public Property Porcentaje() As Integer
05 Get
06 Return porcentajeGuardado
07 End Get
08 Set(ByVal value As Integer)
09 If (valor < 0) Then
10 porcentajeGuardado = 0
11 ElseIf (valor > 100) Then
12 porcentajeGuardado = 100
13 Else
14 porcentajeGuardado = valor
15 End If
16 End Set
17 End Property
18 End Class
Puede crear propiedades de slo lectura o slo escritura al incluir la palabra clave ReadOnly o
WriteOnly antes de la palabra clave Property en la instruccin de declaracin (lnea 04) y
dejando fuera el accesor innecesario.
No es necesario que las propiedades estn unidas a campos. Puede usar propiedades para obtener y
establecer cualquier tipo de valor, y almacenarlo o actuar sobre l de cualquier manera que desee.
Cuando cree instancias de su clase ms adelante en el cdigo, los mtodos pueden llamarse di-
rectamente mediante la instancia de objeto.
Dim ejecutivo As New Empleado
...
ejecutivo.IniciarVacaciones()
La instruccin GoTo
La instruccin GoTo le permite saltar de inmediato a otra ubicacin dentro del procedimiento
actual. El destino de un salto es siempre una etiqueta de lnea, la posicin de una lnea con nom-
bre en el procedimiento actual. Todas las etiquetas de lnea aparecen al principio de una lnea
lgica y terminan con dos puntos.
Es correcto incluir todas las etiquetas que necesite en su cdigo, pero la instruccin GoTo es
uno de esos elementos de Visual Basic que es monitoreado de cerca por las molestas agencias
internacionales de software, como el International Committee To Keep GoTo Always Gone
(ICK-GAG). Ese grupo tambin rastrea los libros de computacin en busca de referencias pe-
yorativas al nombre de su organizacin (en espaol: Comit Internacional para Mantener GoTo
Siempre Ausente), pero no encontrar nada de eso en este libro. Sin embargo, su problema
bsico es que el abuso de las instrucciones GoTo puede llevar a cdigo en forma de espagueti como
el siguiente:
Dim mensajeImportante As String = "Aba"
GoTo Step2
Step6: mensajeImportante &= "AG!"
GoTo Step7
Step3: mensajeImportante &= "co"
GoTo Step4
Step2: mensajeImportante &= "jo "
GoTo Step3
Step5: mensajeImportante &= "CK-G"
GoTo Step6
Step4: mensajeImportante &= "n I"
GoTo Step5
Step7: MsgBox(mensajeImportante)
Algunas personas dicen que este tipo de cdigo es difcil de leer. Otras lo llaman seguridad en el tra-
bajo. No importa cmo lo llame, dificulta en gran medida el mantenimiento y la revisin del cdi-
go. Tal vez debe echar un ojo a su uso de las instrucciones GoTo; si no, alguien ms podra hacerlo.
El propio Visual Basic coloca algunos lmites al uso de GoTo. No puede saltar a ciertas instruc-
ciones de varias lneas que podran producir cdigo o valores de datos inicializados de manera
impropia. Por ejemplo, no puede saltar a la mitad de una instruccin For...Next desde el
exterior de la instruccin, porque no se inicializaran de manera apropiada la variable contadora
del bucle y los rangos de inicio y final.
' ----- Esta instruccin GoTo fallar.
Sin embargo, una vez que se encuentre en el interior del bucle, puede saltar a las etiquetas de
una lnea que tambin aparecen en el bucle, y es aceptable un salto fuera del bucle usando GoTo.
Algunas otras estructuras de varias lneas imponen restricciones similares.
La instruccin Return
No slo puede saltar por un procedimiento empleando GoTo, sino que tambin puede saltar
fuera de un procedimiento en cualquier momento que quiera empleando la instruccin Return.
Por lo general, se sale de un procedimiento cuando el procesamiento alcanza la ltima lnea de
cdigo en el procedimiento; luego contina con el cdigo que llam al procedimiento. La ins-
truccin Return proporciona una manera de salir del procedimiento antes de llegar al final.
En subrutinas, la instruccin Return aparece por s sola como una instruccin independiente:
Return
En funciones, la instruccin debe incluir el valor que se devolver al cdigo de llamada, una
variable, una literal o una expresin que debe coincidir con el tipo de datos del valor de retorno
especificado de la funcin.
Return 25
En versiones anteriores a .NET de Visual Basic se usaba una instruccin Exit para dejar de
inmediato un procedimiento. An tiene soporte en .NET. Existen tres variaciones:
Exit Sub
Sale de una subrutina
Exit Funcin
Sale de una funcin
Exit Property
Sale de una propiedad
Cuando se sale de una funcin, la instruccin Exit Function no incluye una forma para espe-
cificar un valor de retorno. Debe configurar el valor de retorno individualmente asignando un
valor de retorno al nombre de la funcin.
Function DividirConSeguridad(ByVal numerador As Double, _
ByVal denominador As Double) As Double
' ----- El signo "#" hace que un nmero sea Double.
If (denominador = 0#) Then
' ----- Devuelve 0 en una divisin no vlida.
DividirConSeguridad = 0#
Exit Function
End If
Return numerador / denominador
End Function
Esta instruccin Event define un evento llamado SalarioCambiado con un solo argumento,
un valor Decimal. Cualquier manejador de eventos que desee monitorear el evento debe hacer
que coincida la firma de este argumento.
Sub PagoEmpleadoCambiado(ByVal salarioActualizado As Decimal)...
Los eventos pueden ocurrir por cualquier razn que considere necesaria; deben unirse a las
acciones del usuario o el sistema. En esta clase de ejemplo, un evento se dispara cada vez que se
hace un cambio al salario del empleado. La instruccin RaiseEvent realiza el disparo real del
evento, especificando el nombre del evento que se disparar, y un conjunto de argumentos entre
parntesis.
Public Class Empleado
Public Nombre As String
Private salarioActual As Decimal
Los manejadores de eventos son subrutinas ordinarias, pero incluyen la palabra clave Handles
para indicar cul evento se est manejando.
Cuando se establece el salario, la propiedad Salario de la clase Empleado dispara el evento Sa-
larioCambiado utilizando el comando de Visual Basic RaiseEvent. Esto genera una llamada
al manejador de eventos PagoEmpleadoCambiado, que por ltimo despliega el mensaje.
Los eventos construidos en las clases de Windows Forms en .NET trabajan as, pero en lugar de
buscar conmigo un aumento del salario, revisan los clics del ratn y los clacs del teclado. Todos
estos eventos del sistema usan una firma de argumento comn.
Event NombreEvento(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
El argumento sender identifica la instancia del objeto que est disparando el evento, en caso de
que el llamador necesite un examen de sus miembros. El argumento e es un objeto que permite
al llamador enviar datos especficos del evento al manejador mediante una sola instancia de clase.
La clase System.EventArgs no se interpone mucho entre los miembros, pero muchos eventos
usan una clase sustituta que se deriva de System.EventArgs.
A medida que recorramos los captulos de este libro, no habr fin en el nmero de ejemplos de even-
tos que ver y experimentar. Guardar hasta entonces los ejemplos ms complejos e interesantes.
Espacios de nombres
Clases, estructuras, mdulos, enumeraciones, interfaces y delegados (los principales tipos de
.NET) no slo flotan en el cdigo de su aplicacin. Deben agruparse y administrarse en espacios
de nombres. Como se describi en el captulo 1, los espacios de nombres proporcionan una jerar-
qua a sus tipos, una especie de condominio en forma de rbol donde cada tipo tiene un hogar.
Algunos de estos hogares (o nodos), como System, estn habitados por todas esas familias de
tipos que viven all. Otros, como System.Timers, slo pueden tener unos cuantos tipos moran-
do en sus amplios aposentos. Pero cada tipo debe vivir en la jerarqua; ninguno de estos tipos es
lo suficientemente aventurero para independizarse y construir un rancho.
En la raz de la jerarqua se encuentra Global; no es un nodo, sino una palabra clave de Visual
Basic que indica la raz de todas las races. Puede incluir Global cuando haga referencia a sus
espacios de nombres, pero su uso slo es necesario cuando dejarlo fuera causara confusin entre
dos ramas de espacios de nombres.
Esto especifica el espacio de nombres de tercer nivel Forms. Pudo tambin haber escrito:
Global.System.Windows.Forms
Sin embargo, para usar espacios de nombres relativos, debe indicar a su cdigo de Visual Basic
que lo espere. Hay muchos espacios de nombres, y puede haber varios espacios de nombres
Forms en algn lugar de la jerarqua.
Espacios de nombres | 67
le permite hacer referencia a la clase Form como Fred.Form. A diferencia de la lista de impor-
taciones en las propiedades del proyecto, que tiene impacto en todo el proyecto, la instruccin
Imports afecta slo a un archivo de cdigo fuente.
Puede incluir todas las instrucciones de Namespace que necesite en su cdigo. Tambin se da
soporte a la anidacin de espacios de nombres:
Namespace AreaTrabajo
Namespace CosasBasicas
Class MuchosDatos
...
End Class
End Namespace
End Namespace
El espacio de nombres My
Visual Basic 2005 introdujo un nuevo espacio de nombres de nivel superior My, diseado para
simplificar tareas de programacin comunes. Microsoft lo agreg al lenguaje en parte para atraer
a los partidarios renuentes de Visual Basic 6.0 al entorno .NET. Pero no reviste mayor dificul-
tad. My recolecta caractersticas de uso comn que estn dispersas actualmente en la biblioteca
de clase de Framework (FCL, Framework Class Library) y las coloca en una minijerarqua para
acceso conveniente. En realidad no es mucho ms complicado que eso. La jerarqua est orga-
nizada adecuadamente, con secciones de informacin de usuario, aplicacin y especfica de la
computadora. Se usa como cualquier otra parte del marco conceptual, aunque no puede usar
la palabra clave Imports para acceder a sus componentes mediante una ruta relativa.
El espacio de nombres My | 69
Algunas reas del espacio de nombres My son dinmicas; se agregan o eliminan clases a medida
que modifica su cdigo fuente. En aplicaciones de Windows Forms, la rama My.Forms incluye
entradas para cada uno de los formularios del proyecto. A medida que agrega nuevos formula-
rios, se integran automticamente nuevas entradas. Entonces el objeto My.Forms hace referencia
a cada formulario disponible para uso en su cdigo.
My.Forms.Form1.Text = "Bienvenido"
Resumen
Es triste que este captulo haya llegado a su fin. Tal vez sienta que todo pas demasiado rpido;
tal vez sienta que en realidad no aprendi a escribir programas de Visual Basic; tal vez sienta
que un sedante suave sera muy adecuado ahora. Pero no se agobie. Este captulo sirvi como
introduccin a la sintaxis y las caractersticas principales de Visual Basic. Ahora empieza el en-
trenamiento a fondo. Mientras empezamos el eje principal del libro (el Proyecto Biblioteca),
encontrar ejemplos especficos de todas las caractersticas cubiertas slo de manera breve en
este captulo.
Proyecto
En este captulo usaremos la caracterstica de insercin de fragmentos de cdigo de Visual Studio
para insertar cdigo fuente en un marco bsico de cdigo de ejemplo. Los fragmentos de cdigo
son, en esencia, una base de datos jerrquica de texto de cdigo fuente guardado. Si ha instalado
el cdigo de este libro, encontrar code snippets de casi todos los captulos incluido ya en Visual
Studio. En el proyecto de este captulo le mostrar cmo usarlo para agregar cdigo especfico
del captulo en su proyecto.
Como no hemos iniciado oficialmente el Proyecto Biblioteca, el proyecto de este captulo sim-
plemente extender el proyecto Hola, mundo! que desarrollamos en el captulo 1, pero agre-
garemos un poco de diversin. Incluir algunas de las caractersticas del lenguaje que analizamos
en todo este captulo.
ACCESO AL PROYECTO
Cargue el proyecto de cdigo Chap02 (Antes), ya sea mediante las plantillas de Nuevo
proyecto o accediendo directamente al proyecto desde el directorio de instalacin. En
cambio, para ver el cdigo en su forma final cargue el cdigo Chap02 (Final).
El cdigo de ejemplo de cada captulo incluye una versin Antes y una Final. Esta ltima re-
presenta cmo se ver el cdigo cuando se han aplicado todos los cambios de la seccin Proyec-
En este ejemplo se usa una clase separada para procesar el mensaje desplegado. El cdigo para
esta clase aparece como fragmento nmero 1. Para insertar el fragmento, mueva el cursor justo
despus de la lnea marcadora del fragmento #1, que dice:
' *** Inserte aqu el fragmento de cdigo #1.
Para insertar un fragmento mediante mens de Visual Studio, seleccione Editar IntelliSense
Insertar fragmento de cdigo. La secuencia de teclado equivalente es Ctrl-K, Ctrl-X. O escriba un
signo de interrogacin (?) en cualquier lugar del cdigo fuente y despus oprima la tecla Tab. Cual-
quiera de estos mtodos despliega el primer nivel de fragmentos de cdigo (vase la figura 2-4).
Proyecto | 71
De la lista de fragmentos de cdigo, seleccione Programacin en Visual Basic 2008 y luego se-
leccione Cap02. Aparece una lista de elementos de fragmentos de cdigo disponibles para este
captulo (vase la figura 2-5).
Por ltimo, seleccione Elemento 1. Mgicamente aparece el contenido dentro del cdigo fuente.
Todas las inserciones de fragmentos de cdigo de este libro se presentan exactamente de esta
manera.
El fragmento de cdigo 1 inserta la clase DecirHola, parte del espacio de nombres CosasDeHo-
la, de la que aqu aparece una parte:
Namespace CosasDeHola
Friend Class DecirHola
Private mensajeSecreto As String
Private invertirMarca As booleano
Private decodificado As booleano
Estas tres lneas crean una instancia de la clase DecirHola, almacenndola en el campo de la cla-
se DecodificadorHola. No puede leer el primer argumento del constructor? Est codificado!
Es un secreto! Y la marca True indica que se ha invertido para que el secreto sea mayor (no sabe
lo que es!). DecodificarMensaje elimina el secreto al desplazar cada letra lo necesario, aunque
la inversin no se realiza hasta que se llama a ReportarMensaje.
El mtodo ReportarMensaje en realidad no despliega el mensaje. En cambio, dispara un even-
to que pone el mensaje no revuelto a disposicin de un manejador de eventos.
Proyecto | 73
Est sentado en su oficina, surfeando quiero decir, leyendo sobre los recientes temas de la tec-
nologa que ms presionan a los desarrolladores de software. Est ocupado en sus propios asuntos,
cuando de pronto alguien llega hasta su escritorio y le ofrece pagarle por escribir un programa.
Sucede todos los das, en todas las corporaciones, y en ocasiones me hace sentir enfermo.
Pero basta de menciones a mis problemas de salud. Esta persona que est frente a usted le informa
que debe desarrollar una aplicacin de software, tal vez una aplicacin de base de datos con una
interfaz amigable para el usuario. Aunque el conjunto de caractersticas ser especificado por los
usuarios principales, usted, como programador lder (o nico), disear, documentar, desarrollar
y entregar discos que chorrearn software digital distintivo, sorprendente y dinmico. (Diantres!)
Bueno, eso es lo que me sucedi. Un cliente tena una gran coleccin de libros que necesitaba
organizar como una biblioteca tradicional. Al ver que era un arquitecto de software razonable-
mente codependiente, el cliente me pidi que desarrollara algn software para administrar los
libros y eso. De esta solicitud surgi el Proyecto Biblioteca.
A medida que lea este captulo, tendr que conservar mi trabajo diario en mente. Escribo aplica-
ciones personalizadas de Visual Basic para organizaciones pequeas y medianas. La mayor parte
de los proyectos tienen un tamao adecuado para poder completarlos solo, incluidas todas las
necesidades de diseo y documentacin, en menos de un ao. Todos mis proyectos incluyen un
usuario clave, una persona (o en ocasiones un grupo pequeo) que habla por la comunidad
de usuarios. Adems, estos proyectos incluyen a alguien que tiene autoridad para firmar, una
persona autorizada para pagar por el proyecto, o decidir sobre su existencia. Este individuo pue-
de ser el usuario clave.
Si usted estuviera desarrollando, digamos, un reemplazo para Microsoft Word, probablemente
carecera de un usuario clave. Para obtener los requisitos especficos del proyecto, tal vez tenga
que conducir entrevistas de usuario general con docenas de candidatos a usuarios. O podra crear
a una persona, un individuo ficticio que representa a su audiencia de destino. (Para Visual
Studio, Microsoft us tres personas, llamadas Einstein, Elvis y Mort.) Sin importar cul mtodo
aplique, el anlisis general debe guiarlo a la feliz conclusin: un documento de diseo que usar
para construir la aplicacin.
75
Caractersticas administrativas
Los administradores son los bibliotecarios, el personal de tecnologa de la informacin y otros
usuarios que necesitan acceso avanzado a las caractersticas de la aplicacin. Son los princi-
pales usuarios del sistema, no los clientes. La aplicacin incluye las siguientes caractersticas
especficas del administrador:
Una caracterstica de inicio de sesin proporcionar acceso a las caractersticas administrati-
vas de la aplicacin. Slo usuarios autorizados podrn iniciar sesin mediante una contrasea
asignada. Por lo general, la caracterstica estar oculta de la vista de los clientes comunes.
Los administradores podrn ver detalles de los clientes, igual que stos, pero tambin ten-
drn acceso a detalles adicionales. De manera especfica, podrn agregar clientes y adminis-
trar su identidad y sus detalles demogrficos. Los administradores tambin podrn inhabi-
litar un registro de un cliente para evitar prstamos posteriores de artculos.
Los administradores cobrarn y administrarn las multas a los clientes, incluida la capacidad
de administrar archivos no estndar y omitir multas no pagadas.
Los administradores definirn los registros de cada artculo administrado en la base de datos
de inventario del sistema. Esto incluye los elementos bsicos de cada artculo, como ttulo
El Proyecto Biblioteca | 77
Datos e informacin
Su capacidad de proporcionar acceso conveniente y especfico a los datos y la informacin nece-
sarios para los usuarios es la que lo hace a usted, el programador, tan adorable. La mayora de los
usuarios estaban bien antes de las computadoras. Mantenan su informacin en tarjetas de ndice
de 3 5 pulgadas, en blocs o rollos de pergamino, o en tarros de mayonesa hermticamente
cerrados. Pero tenan una razn para moverse a medios de almacenamiento computarizados: la
conveniencia.
Los datos son informacin sin trabajo almacenada por su programa: nombres, nmeros, im-
genes o cualquier otro valor individual. La informacin son datos en un contexto: el registro de
un cliente, un pedido, una presentacin con diapositivas. Cuando proporciona un programa
de calidad que hace que los datos pasen al nivel de la informacin, est proporcionando el
nivel de conveniencia que el usuario necesita para pasar de los frascos de mayonesa a los chips
de silicio.
Facilidad de uso
Si su programa presenta datos e informacin al usuario y en un orden o una organizacin es-
pecficos, pero es difcil de usar, sus usuarios lo odiarn. Lo abominarn. Esparcirn historias
horribles sobre usted, sean ciertas o no. Y cuando aparezcan en grupos, su vehemencia puede
volverse espantosa. He odo historias acerca de un grupo de usuarios de Excel pero tal vez slo
sea un rumor.
Como programador, su trabajo consiste en hacer que el uso de la computadora y el software
que se ejecuta en ella sea lo ms fcil posible. Y aunque tal vez no logre controlar muchas de las
caractersticas bsicas del sistema, usted es el rey cuando se trata de su propio software.
Cuanto ms fcil y til sea el diseo de sus programas, ms felices sern sus usuarios. Pero debo
prevenirlo: facilidad de uso para el usuario siempre significa ms trabajo para el desarrollador.
Siempre. Es una de esas injustas leyes del universo, y no hay manera de evitarla. Pero en ocasiones
lo intentamos, y ponemos al usuario en peligro.
Hace muchos, muchos aos, escrib algunos programas para demostrar la nueva versin de BA-
SIC que se ejecutaba en el procesador Motorola 6809. Esta versin poda manejar programas del
doble de tamao que la versin anterior: unos enormes 32 KB de cdigo fuente. Se me encarg
que probara el sistema, escribiendo programas grandes que demostraran la nueva funcionali-
Uso comn
De manera constante, Microsoft presume de innovacin, y la capacidad de innovar ha hecho que
el software avance a un ritmo incomparable. Por desgracia, los usuarios slo pueden manejar
fragmentos de innovacin a la vez. Considere el telfono. Hered un viejo telfono en una caja
de roble de mis abuelos (vase la figura 3-1).
Es un telfono divertido y muy fcil de usar. Cuando alguien quiere hacer una llamada, levanta
el auricular y presiona la manija en el lado de la unidad por unos tres o cuatro segundos. Cuando el
operador toma la lnea, le dice a quin desea llamar. Qu podra ser ms simple? Qu podra
ser ms amigable con el usuario? Qu podra ser ms caro que una llamada con la ayuda del
operador? Pero era simple, y todos saban de manera instintiva cmo usarlo.
Los telfonos de hoy en da usan botones en lugar de manijas. Casi todos los botones son sim-
ples dgitos que permiten marcar directamente un nmero de telfono. Pero tambin hay otros
botones: Mute, Redial, Pause, Flash, # y *. Me da miedo oprimir el botn Flash, y qu hacen
los botones SND y CLR en los telfonos celulares? El problema no es con los propios botones,
sino que cada telfono tiene una seleccin diferente de botones. Han perdido la capacidad de uso
comn que haca que los telfonos de manija fueran fciles de usar. Seguro que tienen muchas
caractersticas ms, pero si la persona promedio no puede imaginar cmo se usa esa funcionali-
dad, cul es el beneficio?
De regreso al software: aun los programas nuevos e innovadores deben retener algunas funciones
de uso comn en el sistema operativo y con otros programas instalados. Mientras habla con los
usuarios acerca de sus necesidades y piensa en los grandes avances de la tecnologa del software
que les proporcionar, no olvide la capacidad de uso comn. No se olvide de una de las necesida-
des centrales de los usuarios: no ser sobrecargados por nuevas maneras de hacer tareas que creen
que ya pueden hacer. Los usuarios necesitan consistencia.
La vida de un proyecto
Los proyectos tienen un tiempo de vida propio. Algunos son de corta duracin; he escrito pro-
gramas que se usaron durante dos semanas y luego se descartaron cuando se complet el proyec-
to del negocio. Algunos programas duran para siempre, con mejoras continuas hechas sobre una
serie de iteraciones a la versin. Estoy escribiendo ahora mismo uno de esos programas.
Como desarrollador, debe estar al tanto del tiempo de vida de su proyecto. Una vez que com-
prenda ste, puede aplicar procesos de negocios a cada fase importante de la vida del proyecto.
A las habilidades necesarias para guiar un proyecto a su conclusin o a travs de cada versin
sucesiva del proyecto se les denomina de manera colectiva administracin del proyecto. Muchas
organizaciones tienen administradores de proyecto dedicados, sobre todo en el caso de proyectos
ms grandes. Si son pequeos, el programador puede bastarse para soportar la carga de la admi-
nistracin del proyecto.
Por fortuna, la mayora de los administradores de proyectos no slo hacen que las cosas avancen
(aunque me he encontrado con algunos que es lo nico que hacen). Trabajan dentro de un sistema,
un marco conceptual de la metodologa del proyecto, un sistema de administracin que mantiene el
plan del proyecto dentro de sus lmites. En el resto de este captulo tratar los puntos ms importan-
La vida de un proyecto | 83
Logros
importantes
Logro
importante
Logro
importante
tes de un marco conceptual tpico. Si regresa a la librera donde recibi un descuento por comprar
este libro, encontrar un estante lleno de recursos relacionados con marcos conceptuales de la meto-
dologa del proyecto. Aun Microsoft tiene sus propias recomendaciones, llamadas marco conceptual
de soluciones de Microsoft (MSF, Microsoft Solutions Framework). Debido a que casi todos los pro-
yectos que Microsoft desarrolla cambian de nombre a travs de sucesivas versiones, el MSF es cclico
o iterativo. En el caso de aplicaciones que, por lo menos ahora, slo tendrn una versin importante,
un mtodo lineal funcionar bien. (Vase la figura 3-2 para conocer ambos mtodos.)
Como este libro terminar con un proyecto completo y como mi editor no ha llegado a acuerdos
sobre los derechos de la siguiente edicin ni de la pelcula, usar el mtodo lineal. Sin importar
el mtodo que use, varios eventos importantes se presentarn entre el inicio y el final de la lnea
o iteracin, empezando con la patada inicial del proyecto.
Documentacin
Es importante documentar todo, mientras avanza por el proyecto, sobre todo en las primeras
etapas de diseo. Esto le ayudar no slo a recordar aspectos esenciales del proyecto ms adelan-
te, durante la fase de desarrollo, sino tambin a mantener informadas sobre el estado del proyec-
to a todas las partes que participan en l. Imagine esta conversacin con su jefe:
Diseo y planeacin
Mi madre me dio hace poco un pedazo viejo de papel con el dibujo de los planos de una casa.
Cuando examin ese papel con ms detalle, encontr que el diseo coincida con la casa en que
crec, una casa que ya no es parte, por fortuna, de los bienes races de la vasta familia Patrick.
La vida de un proyecto | 85
Cambios al proyecto
En general, los desarrolladores siempre completan a tiempo los proyectos, bajo el presupuesto
y con todas las caractersticas incluidas, y el usuario satisfecho instala gozosamente el software,
emplendolo a diario para cumplir con los exigentes retos del trabajo.
Ja, ja. Ahora que se ha redo con ganas, sigamos con el captulo. Muchos proyectos avanzan bien
y suelen apegarse al plan acordado por el usuario y el desarrollador. Pero otros no. En algn lugar
intermedio de la vida del proyecto ocurre un cambio. Tal vez se deba a dificultades para construir
el proyecto, lo que lleva a un cambio en el calendario. Tal vez se deba a nuevos requisitos en las
necesidades (o los deseos) del usuario en el proceso relacionado del negocio, lo que lleva a un
cambio en el alcance.
Tal vez se hagan cambios menores al proyecto que no preocupen demasiado al usuario ni al
programador. Pero otros cambios pueden tener un impacto significativo en el costo, el calen-
dario, o ambos. Estos cambios pueden documentarse y acordarse entre ambas partes mediante
un documento de cambio del alcance, al que en ocasiones se le denomina orden de cambio. Si el
equipo de desarrollo debe ajustar el calendario, o reducir o cambiar las caractersticas incluidas
de la aplicacin, la comunicacin de esto al usuario mediante documentos de cambio evita que
el usuario se vea sorprendido al esperado final del proyecto.
La vida de un proyecto | 87
Implementacin y distribucin
Ahora el proyecto est listo para su instalacin en la estacin de trabajo de cada usuario. El
mtodo de distribucin y entrega depende del proyecto y la audiencia de destino. Trtese de
una distribucin en la red interna, la distribucin en CD a un nmero pequeo de lugares, la
distribucin en Web al pblico en general, o el empaquetado del producto para venta en tiendas,
el equipo de programacin por lo general est limitado a la interaccin con las estaciones de
trabajo de destino. Por supuesto, esto puede cambiar rpidamente una vez que la lnea telefnica
de soporte tcnico entre en funcionamiento.
Soporte continuo
Despus de que la poblacin de usuarios ha usado el producto durante un tiempo, los informes
de errores en la aplicacin o de mejoras deseadas pueden inundar al equipo de desarrollo. stos
pueden reunirse para tomarse en cuenta en versiones futuras, o atenderse de inmediato en actua-
lizaciones de versin de servicio del producto. Como podra tener varias versiones del producto
en uso dentro de su comunidad de usuarios, es esencial que identifique y pruebe contra cual-
quier versin en particular. Los sistemas de control de cdigo fuente (incluido Microsoft Visual
SourceSafe, que se incluye en algunas ediciones de Visual Studio y Team Foundation Server) le
permiten mantener imgenes especficas de la versin en el cdigo fuente. Tambin puede man-
tener un archivo de ejecutables de versin y otros archivos para prueba posterior.
Si su aplicacin se escribi para un solo cliente o una organizacin, puede haber un periodo de
garanta en que se corregirn de manera gratuita algunos o todos los errores reportados durante
la vigencia de esa garanta.
La vida de un proyecto | 89
Proyecto
Es necesario completar muchas tareas antes de que empiece la codificacin en un proyecto
grande. La codificacin real del Proyecto Biblioteca empezar en el captulo 5. En este captulo
completaremos el documento de acuerdo del proyecto que describe las caractersticas del Pro-
yecto Biblioteca.
En este captulo no se incluye una plantilla de proyecto de Visual Studio que pueda cargar y
examinar en Visual Studio. En cambio, debe acceder al subdirectorio del captulo 3 del directorio
de instalacin del libro. Contiene tres archivos:
Acuerdo de proyecto.doc
Es el documento principal del proyecto que identifica las caractersticas del proyecto com-
pletado. Es un acuerdo entre los representantes del desarrollador y el usuario. Las desviacio-
nes a este documento slo ocurren a travs del proceso de Orden de cambio.
Orden de cambio.doc
Es un archivo empleado para modificar el proyecto original mediante el proceso de Orden
de cambio. Cuando se usa este documento, se incluye una descripcin del cambio que se
har al proyecto, y cualquier impacto en el calendario y el costo.
Aceptacin del proyecto.doc
Este archivo se usa cuando se completa el proyecto, y el usuario est listo para aceptar el
producto terminado. Este documento combina los elementos de la Prueba de criterios de
aceptacin y Aceptacin del proyecto descritos en pginas anteriores del captulo.
Por favor, sintase con la libertad de usar estos documentos para apoyar sus propios proyectos.
Sin embargo, al equipo legal de OReilly Media le gustara recordarle que si decide usarlos, lo
debe hacer por su propia cuenta y riesgo. Estos documentos slo tienen el objetivo de servir
como ejemplos. Debe hablar con un abogado de su localidad si desea crear documentos similares
y hacer que representen responsabilidades contractuales.
En el resto de esta seccin se presenta el Acuerdo de proyecto.doc llenado con los detalles del
Proyecto Biblioteca. Su contenido principal es una copia de los elementos incluidos en la lista
con vietas de la seccin 3.1, casi al principio del captulo. Tambin documenta algunos otros
requisitos especficos del proyecto e incluye un estimado clsico de costos del proyecto. Para fines
de demostracin, use una tasa por hora de 25.00 dlares.
Pgina 1
Acuerdo de proyecto | 91
Caractersticas administrativas
Una caracterstica de inicio de sesin proporcionar acceso a las caractersticas administrati-
vas de la aplicacin. Slo usuarios autorizados podrn iniciar sesin mediante una contrasea
asignada. Por lo general, la caracterstica estar oculta de la vista de los clientes comunes.
Los administradores podrn ver detalles de los clientes, igual que stos, pero tambin ten-
drn acceso a detalles adicionales. De manera especfica, podrn agregar clientes y adminis-
trar su identidad y sus detalles demogrficos. Los administradores tambin podrn inhabi-
litar un registro de un cliente para evitar prstamos posteriores de artculos.
Los administradores cobrarn y administrarn las multas a los clientes, incluida la capaci-
dad de administrar archivos no estndar y omitir multas no pagadas.
Los administradores definirn los registros de cada artculo administrado en la base de datos
de inventario del sistema. Esto incluye los elementos bsicos de cada artculo, como ttulo
y autores. Cada artculo incluir una o ms copias, lo que representa artculos fsicos que
pueden prestarse. Las copias tienen asignados cdigos de barras.
Adems de los artculos y las copias, los administradores definirn todos los valores de apo-
yo y las listas, incluidos nombres de autores y categoras, lista de tipos de medios, editores,
nombres de las series de libros, cdigos de estatus que identifican la disposicin de la copia
de cada artculo y ubicaciones.
Pgina 3
Acuerdo de proyecto | 93
Datos. Bases de datos. Pareciera tener sentido. Si tiene datos, necesita ponerlos en algn lugar.
Y qu mejor lugar donde ponerlos que en una base de datos?
Slo para asegurarme de que tuve todas las bases cubiertas, hice una rpida bsqueda en
Internet de una definicin til. Qu impresin. De acuerdo con casi todos los sitios Web que
encontr, una base de datos es una coleccin de datos organizados para fcil recuperacin por
parte de una computadora. Con una definicin como sa, casi todo lo que pongo en mi sistema
se almacena en una base de datos. Todos los archivos de disco estn organizados para fcil acceso.
Los correos electrnicos que he guardado puedo ordenarlos por tema, fecha de recepcin o remi-
tente, de modo que tambin deben estar en una base de datos. Incluso este documento permite
la bsqueda y puede ordenarse de cualquier manera que desee. Es una base de datos?
95
ID de ID de ID de Nombre ID de
registro pedido cliente del cliente producto Producto Precio Cantidad
92231 10001 AA1 Juan Campos BEV01COF Caf 399 3
92232 10001 AA1 Juan Campos BRD05RYE Pan de centeno 26.80 1
92233 10002 BW3 Arturo Ramos BEV01COF Caf 39.90 1
92234 10003 BW3 Arturo Ramos BEV01COF T 39.90 2
92235 10004 CC1 Carlos Chvez CHP34PTO Papas fritas 10.90 7
Realmente es conveniente poner toda su informacin en una tabla. Los datos importantes apare-
cen a simple vista en una disposicin agradable y ordenada, y es fcil ordenar los resultados con
base en una columna determinada. Por desgracia, esta tabla de pedidos tiene muchas repeticiones.
Nombres de cliente y de productos se repiten varias veces. Adems, aunque el ID de producto
BEV01COF indica caf, una de las lneas la presenta como T. Algunos problemas adiciona-
les son inherentes en datos que estn colocados en una sola tabla de datos de archivo simple.
Mr. Codd, quien fue un brillante cientfico de la computacin, tambin vio este problema. Pero
en lugar de slo sentarse y quejarse como yo, desarroll una solucin: la normalizacin. Al dividir
los datos en tablas separadas con subconjuntos de datos, asignar un identificador nico para cada
registro/fila en cada tabla (una clave principal) y hacer algunos cuantos ajustes adicionales, los
datos podan normalizarse para eficiencia en el procesamiento e integridad de datos. En el caso
de los pedidos de ejemplo de la tabla 4-1, los datos podan normalizarse en tres tablas separadas:
una para los elementos de lnea de pedidos, otra para clientes y una ms para productos (vanse
las tablas 4-2, 4-3 y 4-4, respectivamente). En cada tabla he puesto un asterisco junto al ttulo
de la columna que acta como la columna de clave principal.
Para obtener resultados combinados de varias tablas a la vez, una (o vincule) sus campos coinci-
dentes. Por ejemplo, puede vincular el campo ID de cliente en la tabla de artculos de lnea
con el campo de clave principal coincidente ID de cliente en la tabla de clientes. Una vez
unidos, los detalles para un solo registro de artculo de lnea combinado pueden presentarse con
el nombre de cliente completo que coincide. Es lo mismo para uniones directas con cualquier
par de tablas que tengan campos vinculables. En la figura 4-1 se muestran las relaciones entre las
tablas de cliente, producto y lnea de pedido.
Artculos de lnea
Clientes Productos
ID de registro
ID de cliente ID de producto ID de producto
Nombre del cliente ID de pedido Precio unitario
ID de cliente
Cantidad
Para unir tablas, las bases de datos relacionales implementan lenguajes de consulta que le permiten
manipular los datos empleando lgebra relacional (de la que se deriva el trmino base de datos re-
lacional). El ms popular de estos lenguajes, SQL, usa frases simples similares al ingls para unir,
ordenar, resumir y recuperar los valores de datos que necesita. La instruccin primaria, SELECT,
proporciona caractersticas bsicas de seleccin y recuperacin de datos. Otras tres instruccio-
nes comunes, INSERT, UPDATE y DELETE, le permiten manipular los registros almacenados en
cada tabla. Juntas, estas cuatro instrucciones integran los comandos principales del lenguaje de
manipulacin de datos (DML, Data Manipulation Language) de SQL. Adems, SQL incluye ins-
trucciones de lenguaje de definicin de datos (DDL, Data Definition Language) que le permiten
disear las tablas usadas para contener los datos, adems de otras caractersticas de base de datos.
Mostrar ejemplos de varias instrucciones SQL en pginas posteriores de este captulo.
Sistemas especficos del vendedor, como SQL Server de Microsoft, Oracle de Oracle, Access de Mi-
crosoft y DB2 de IBM, extienden estas caractersticas centrales de DDL y DML mediante herramien-
Debido a que algunos lectores de Programacin en Visual Basic 2008 tal vez
slo tengan acceso a la SQL Server 2005 Express Edition (y la herramien-
ta relacionada SQL Server 2005 Management Studio Express), todos los
ejemplos de este libro estn diseados para usarse con esa edicin del motor
de la base de datos. Esto slo tiene impacto las pocas veces que me refiero
especficamente a las herramientas de cliente. Todas las instrucciones de
SQL (tanto DDL como DML) presentadas en este libro y en el cdigo
fuente del Proyecto Biblioteca funcionarn con cualquier edicin de SQL
Server 2005 o SQL Server 2008.
Aunque Microsoft sigue actualizando y vendiendo Microsoft Access, se recomienda cada vez
ms que los desarrolladores profesionales usen y distribuyan bases de datos en formato de SQL
Server. Microsoft le permitir incluso redistribuir SQL Server 2005 Express Edition con su
SQL
Hacer negocios en Japn es muy fcil, una vez que conoce el idioma. Lo mismo resulta
cierto para SQL Server: es muy fcil manipular y acceder a los datos una vez que conoce el
lenguaje. En este caso, el lenguaje es SQL o Structured Query Lenguaje (lenguaje estructu-
rado de consultas). Desarrollado originalmente por IBM, SQL se ha vuelto desde entonces
un estndar en la industria de las bases de datos. Bueno, una especie de estndar, porque al
igual que Estados Unidos e Inglaterra, SQL Server de Microsoft y Oracle de Oracle son dos
bases de datos relacionales que estn divididas por un lenguaje comn. Las partes centrales
del lenguaje SQL son muy consistentes entre vendedores, pero cada proveedor agrega gran
cantidad de caractersticas adicionales y variaciones de sintaxis diseadas por los imitadores
de Edgar Codd.
En esta seccin se describen las instrucciones DDL y DML que sern ms tiles en nuestro de-
sarrollo del programa Biblioteca. Estar contento de saber que SQL no es muy puntilloso en el
formato de las diversas instrucciones. Se ignoran las distinciones entre maysculas y minsculas;
SELECT es lo mismo que select y que SeLeCt. (El cdigo tradicional de SQL est principal-
mente en maysculas. Yo uso stas para todas las palabras clave, y las mezclo para tablas, campos
y otros elementos personalizados. No importa lo que usted elija, la consistencia es importante.)
Adems, emplee los espacios en blanco como ms le convenga. Puede poner instrucciones en
una lnea gigantesca, o colocar cada palabra en una lnea separada. La nica ocasin en que s
importan los espacios en blanco y las maysculas y minsculas es en las cadenas reales de texto
de datos; no importa lo que escriba, as se quedar.
Por lo general, las instrucciones SQL terminan con un punto y coma, pero algunas herramientas
no requieren que lo incluya, y otras imponen que lo excluya. Cuando use las herramientas vi-
suales de cliente de SQL Server (Management Studio y Management Studio Express), el punto
y coma es opcional, pero representa una buena idea incluirlo cuando est usando juntas varias
instrucciones, una tras otra. Las instrucciones de SQL usadas en cdigo de Visual Basic nunca
incluyen puntos y coma.
Ms adelante, cuando revise una secuencia de comandos de SQL que yo haya escrito, ver la
palabra GO de vez en cuando. En SQL Server este comando indica Para todas las dems instruc-
ciones que aparecen hasta ahora, sigue adelante y procsalas ahora.
Instrucciones DDL
Esto puede ser un golpe para usted, pero antes de que pueda almacenar datos en una tabla, tiene
que crear sta. SQL tiene la herramienta para hacerlo: la instruccin CREATE TABLE. Es una de
las muchas instrucciones DDL. La sintaxis bsica es muy sencilla:
Slo llene las partes que est listo para poblar (es decir, los datos). Los nombres de tablas y campos
estn conformados por letras y dgitos; puede incluir espacios y algunos otros caracteres espe-
ciales, pero dificulta la codificacin posterior (por ello, en la tabla real de nuestro proyecto no
utilizaremos acentos, aunque SQL Server los acepta). Cada vendedor tiene su propia coleccin
de tipos de datos; me apegar aqu a las versiones de SQL Server. Las opciones le permiten espe-
cificar cosas como si los campos requieren datos, si representa la clave principal de la tabla, y
otras restricciones similares. Las extensiones de la sintaxis le permiten configurar restricciones que
aplican a toda la tabla, ndices (que le permiten ordenar o buscar una columna determinada ms
rpidamente) y especificaciones de almacenamiento de datos.
He aqu una instruccin CREATE TABLE de ejemplo que podra usarse para los elementos de
lnea de pedido de la tabla (revise como referencia la tabla 4-4):
CREATE TABLE ElementosLinea
(
IDRegistro bigint IDENTITY PRIMARY KEY,
IDPedido bigint NOT NULL,
IDCliente varchar(20) NOT NULL
REFERENCES Clientes (IDCliente),
IDProducto varchar(20) NOT NULL,
Cantidad smallint NOT NULL
)
La palabra clave IDENTITY permite que SQL Server se encargue de llenar el campo IDRegistro
con datos; usar un contador secuencial para proporcionar un valor nico para IDRegistro con
cada nuevo registro. La clusula PRIMARY KEY identifica el campo IDRegistro como el valor
de identificacin nico para cada registro de la tabla. Los tipos de datos bigint y smallint
indican campos de entero de tamao apropiado, y el tipo varchar proporciona espacio para tex-
to, hasta la longitud mxima especificada entre parntesis (20 caracteres). La clusula opcional
REFERENCES identifica una relacin entre esta tabla ElementosLinea y otra llamada Clientes;
valores en el campo ElementosLinea.IDCliente coinciden con los valores clave del campo
Clientes.IDCliente. (Observe la sintaxis de punto que se usa para separar los nombres de
tabla y campo. Se presenta por todos lados en SQL.) A las referencias entre tablas se les conoce
como referencias externas.
Si necesita hacer cambios a la estructura o las opciones de una tabla o sus campos despus de crea-
da, SQL incluye una instruccin ALTER TABLE que puede cambiar casi todo en la tabla. Adems,
hay una instruccin DROP TABLE relacionada, que se usa para deshacerse de la tabla y todos sus
datos. Tal vez quiera evitarla en datos de produccin en vivo, porque los usuarios tienden a mos-
trarse un poco irritables cuando los datos desaparecen de sbito de la superficie de la Tierra.
En la tabla 4-5 se presenta un resumen de tipos de datos disponibles usados en SQL Server.
SQL | 101
Instrucciones DML
Aunque las instrucciones DDL son poderosas, no se usan mucho. Una vez que crea los objetos
de su base de datos, no hay mucho espacio para modificaciones. Las instrucciones DML son ms
tiles para navegar por datos cotidianos.
La instruccin INSERT agrega registros de datos a una tabla. Los datos se agregan a una tabla de
registro en registro. (Una variacin de INSERT le permite insertar varios registros, pero deben
provenir de otro origen de tabla existente.) Para usar la instruccin INSERT, especifique la tabla
y los campos de destino, y luego los valores individuales que se pondrn en cada campo. Un valor
de datos corresponde a cada nombre de columna de datos especificado.
INSERT INTO ElementosLinea
(IDPedido, IDCliente, IDProducto, Cantidad)
VALORES (10002, 'BW3', 'BEV01COF', 1)
Suponiendo que sta va con la instruccin CREATE TABLE escrita antes, esta accin de insertar
agregar un nuevo registro a la tabla ElementosLinea con cinco nuevos campos (cuatro
campos especificados, ms la clave principal que se agrega automticamente al campo IDRegis-
tro porque estaba marcado como IDENTITY). SQL Server tambin hace gran cantidad de
revisiones de integridad de datos. Cada campo de datos que agregue debe ser del tipo correcto,
pero usted ya esperaba eso. Como diseamos el campo IDCliente para que sea una referencia a
la tabla Clientes, la insercin fallar si el cliente BW3 no existe an en la tabla Clientes.
Pueden incluirse las literales numricas necesarias en sus instrucciones SQL sin calificacin adicio-
nal. Las cadenas de literales siempre estn entre comillas, como se hace para el cliente y el ID de
producto en esta instruccin INSERT. Si necesita incluir una comilla sencilla en la literal, ingrsela
dos veces:
SQL | 103
Estos valores de fecha y hora aceptan cualquier formato reconocido, aunque debe usar uno que
no facilite la mala interpretacin por parte de SQL Server.
Muchos tipos de campo dan soporte a un valor sin signo, un valor que indica que el campo no
contiene datos. A ese valor se le conoce como nulo, y se especifica en SQL Server con la palabra
clave NULL. No puede asignar NULL a campos de clave principal, ni a ningn campo marcado
con la opcin NOT NULL.
Para eliminar un registro previamente agregado, use la instruccin DELETE:
DELETE FROM ElementosLinea WHERE IDRegistro = 92231
La instruccin DELETE incluye una clusula WHERE (la parte WHERE IDRegistro = 92231).
Las clusulas WHERE le permiten indicar uno o ms registros en una tabla al hacer comparaciones
con campos de datos. Sus clusulas WHERE pueden incluir palabras clave Y y O para unir varias
condiciones, y parntesis para agrupar.
DELETE FROM ElementosLinea WHERE IDPedido = 10001
Y IDProducto = 'BRD05RYE'
Una instruccin DELETE puede eliminar cero, uno o 1 000 registros, de modo que la precisin
en la clusula WHERE es importante. Para eliminar todos los registros de una tabla, excluya por
completo la clusula WHERE.
DELETE FROM ElementosLinea
La instruccin UPDATE tambin usa una clusula WHERE para modificar valores en registros de
tabla existentes.
UPDATE ElementosLinea SET Cantidad = 4
WHERE IDRegistro = 92231
Las asignaciones se hacen a campos con la clusula SET; ponga el nombre de campo (Cantidad)
a la izquierda del signo de igual, y el nuevo valor a la derecha (4). Para asignar varios valores a la
vez, separe cada asignacin con una coma. Tambin puede incluir frmulas y clculos.
UPDATE ElementosLinea SET Cantidad = Cantidad + 1,
IDProducto = 'BEV02POP'
WHERE IDRegistro = 92231
Al igual que con la instruccin DELETE, UPDATE puede actualizar cero, uno o muchos registros
con base en los registros que coinciden con la clusula WHERE.
La instruccin DML final, y una de las ms usadas, es SELECT.
SELECT IDProducto, Cantidad FROM ElementosLinea
WHERE IDRegistro = 92231
SELECT rastrea una tabla (ElementosLinea), buscando todos los registros que coinciden con un
criterio determinado (IDRegistro = 92231), y devuelve una tabla ms pequea que contiene
Esta consulta devuelve todos los registros de la tabla sin un orden determinado. El asterisco (*)
significa incluir todos los campos.
La clusula opcional ORDER BY devuelve los resultados en un orden especfico.
SELECT * FROM ElementosLinea
WHERE Cantidad > 5
ORDER BY IDProducto, Cantidad DESC
Esta consulta devuelve todos los registros que tienen un valor de campo Cantidad mayor de
cinco, y ordena los resultados primero por la columna IDProducto (en orden ascendente) y
luego por la cantidad numrica (en orden descendente, especificado por DESC).
Las funciones de agregacin y las caractersticas de agrupacin le permiten resumir resultados del
conjunto ms largo de datos. La siguiente consulta documenta la cantidad total ordenada para
cada producto de la tabla:
SELECT IDProducto, SUM(Cantidad) FROM ElementosLinea
GROUP BY IDProducto
Puede usar uniones para vincular los datos de dos o ms tablas distintas. La siguiente consulta
une las tablas ElementosLinea y Cliente en sus columnas coincidentes IDCliente. Esta ins-
truccin SELECT tambin demuestra el uso de las abreviatura de tabla (los prefijos LI y CU)
agregados mediante las clusulas AS; no suelen ser necesarias, pero ayudan a que sea legible una
consulta ms compleja.
SELECT LI.IDPedido, CU.NombreCliente, LI.IDProducto
FROM ElementosLinea AS LI INNER JOIN Cliente AS CU
ON LI.IDCliente = CU.IDCliente
ORDER BY LI.IDPedido, CU.NombreCliente
Esta tabla usa una unin interna, uno de los cinco tipos principales de unin, cada uno de los
cuales regresa conjuntos diferentes de registros basados en la relacin entre la primera (izquierda)
y la segunda (derecha) tabla de la unin:
Unin interna
Devuelve slo los registros donde hay una coincidencia en los campos vinculados. Este tipo
de unin usa las palabras clave INNER JOIN.
Unin externa izquierda
Devuelve todos los registros de la tabla de la izquierda y slo los registros de la tabla de la dere-
cha en que hay una coincidencia en los campos calculados. Si un registro de una tabla a la iz-
quierda no tiene una coincidencia, acta como si todos los campos de la tabla de la derecha de
ese registro contuvieran valores NULL. Este tipo de unin usa las palabras clave LEFT JOIN.
Uno de sus usos podra ser unir las tablas Productos y ElementosLinea. Podra devolver
una lista del nombre completo del producto para todos los productos disponibles, adems
SQL | 105
Resumen
Casi todas las aplicaciones de Visual Basic estn orientadas al mundo de los negocios y estn
diseadas para interactuar con algn tipo de base de datos. Es importante la comprensin del
sistema de la base de datos usada con su aplicacin; an ms importante es la documentacin de
las caractersticas especficas de la base de datos que incorpora en su aplicacin.
Debido a la influencia de las bases de datos relacionales y del lenguaje SQL en la industria de las
bases de datos, no ser difcil encontrar una gran cantidad de recursos que le ayudarn a crear
instrucciones de SQL y consultas complejas de anlisis de datos. El Proyecto Biblioteca de este
libro usa SQL Server 2005, pero debido al uso generalmente consistente de las caractersticas
centrales del lenguaje SQL, la aplicacin podra tambin usarse de manera fcil en Oracle, Mi-
crosoft Access, o cualesquiera otras bases de datos relacionales.
Proyecto
Para ayudar a mi desarrollo de proyectos de base de datos de Visual Basic, siempre escribo un do-
cumento Kit de recursos tcnicos antes de empezar la codificacin real de la aplicacin. La parte
central de este documento de procesamiento de palabras consta de la documentacin en el nivel de
la tabla y los campos para la base de datos asociada a la aplicacin. Tambin se incluyen los formatos
de todos los archivos de datos de configuracin y personalizados, un mapa de las pginas de ayuda en
lnea, e informacin acerca de productos de terceros usados en la aplicacin. Dependiendo del tipo
de aplicacin, mis expectativas para el usuario y los trminos de cualquier contrato, puedo propor-
cionar nada, algo o todo el contenido del kit de recursos para la comunidad de usuarios.
Empecemos el kit de recursos tcnicos para el Proyecto Biblioteca al disear y documentar las
tablas de la base de datos que habr de usar la aplicacin. Este kit de recursos aparece en el di-
rectorio de instalacin del libro, en el subdirectorio del captulo 4, y contiene los tres archivos
siguientes:
Kit de recursos de la biblioteca ACME.doc
Una versin en Microsoft Word de la documentacin tcnica para el proyecto.
Kit de recursos de la biblioteca ACME.pdf
Una segunda copia del kit de recursos tcnicos, esta vez en formato Adobe Acrobat (PDF).
Script de creacin de base de datos.sql
Una secuencia de comandos de base de datos de SQL Server usada para construir las tablas
y los campos reales en la base de datos.
Proyecto | 109
NombreGrupo. Cada registro en esta tabla define un solo grupo de seguridad. Los bibliote-
carios y otros administradores pertenecen a un grupo de seguridad separado.
ActividadGrupo. Esta tabla conecta registros de la tabla Actividad con registros de la tabla
NombreGrupo (una relacin varias a varias) para establecer las actividades que puede realizar
un grupo de seguridad.
NombreUsuario. Esta tabla contiene los registros reales para cada bibliotecario o administrador.
Cada registro incluye la contrasea del usuario y los parmetros del grupo de seguridad.
Proyecto | 111
SerieCodigo. Algunos artculos aparecen como parte de una serie o coleccin ms grandes.
Esta tabla define los nombres de coleccin y serie.
Artculos de la biblioteca
Las tablas de esta seccin administran el inventario real de artculos. Debido a que la biblioteca
podra poseer ms de una copia de un solo artculo, estas tablas administran el artculo con
nombre y sus copias individuales por separado.
ArticuloConNombre. Un artculo de la biblioteca, como un libro, CD o revista. Esta tabla
representa un artculo general y no la copia real del artculo.
Proyecto | 113
CopiaArticulo. Una sola copia de un artculo con nombre. Copias separadas del mismo art-
culo aparecern como registros separados en esta tabla.
Editor. Una organizacin que publica libros o algn otro tipo de medio.
Autor. Alguien que escribe, edita, ilustra o colabora de alguna otra manera un libro o ar-
tculo de medios. En todos los casos, cuando aparece el trmino autor en esta tabla, hace
referencia a alguien que colabor con el artculo.
AutorArticulo. Un autor, editor, etc., de un artculo con nombre especfico. Esta tabla esta-
blece una relacin varias a varias entre las tablas ArticuloConNombre y Autor.
Clave. Palabras personalizadas que pueden aplicarse a artculos con nombre para facilitar
la bsqueda.
Proyecto | 115
TemaArticulo. Conecta un tema con un artculo con nombre mediante una relacin varias a
varias entre las tablas ArticuloConNombre y Tema.
CopiaCliente. Esta tabla administra las copias de los artculos que se han prestado a un clien-
te, o las copias de artculos que se prestaron antes y ya se regresaron.
Proyecto | 117
EtiquetaCodigoBarras. Describe la plantilla para una sola etiqueta en una hoja de clculo de
cdigo de barras. En una hoja puede haber cualquier nmero de etiquetas, pero todas tienen
la misma forma y el mismo formato.
Proyecto | 119
ValorSistema. Esta tabla almacena configuraciones diversas de toda la empresa que se aplican
a cada estacin de trabajo. Las configuraciones especficas de estaciones locales se almacenan
en cada equipo, no en la base de datos.
Los siguientes valores del sistema se definen en este momento. El nombre del cdigo aparece
en el campo NombreValor. El valor correspondiente aparece en el campo DatosValor.
CodCodigoBarras39
El cdigo de barras especificado est en formato de cdigo 39 o cdigo 3 de 9?
En este caso, se colocar un asterisco antes y despus del nmero de cdigo de barras
antes de que se imprima en la etiqueta. Use un valor de 0 para False o cualquier valor
distinto de cero para True (1 es el preferido). Si se omite o es NULL, se supone False.
FuenteCodigoBarras
El nombre de la fuente usada para imprimir cdigos de barras. Esta fuente debe insta-
larse en cualquier estacin de trabajo que despliegue o imprima cdigos de barras. No
es necesario para escanear cdigos de barras.
Proyecto | 121
Los campos incluidos en cada instruccin CREATE TABLE aparecen como listas delimitadas por
comas, todo entre parntesis. Cada campo incluye una opcin NULL o NOT NULL que indica si
pueden usarse valores NULL en ese campo. La opcin PRIMARY KEY especifica automticamente
NOT NULL.
Algunas instrucciones crean tablas que vinculan otras dos tablas en una relacin varias a varias.
Un ejemplo es la tabla ActividadGrupo, que conecta la tabla NombreGrupo con Actividad.
CREATE TABLE ActividadGrupo
(
IDGrupo bigint NOT NULL,
IDActividad bigint NOT NULL,
PRIMARY KEY (IDGrupo, IDActividad)
);
La tabla Autor tiene una sola clave principal, de modo que la opcin PRIMARY KEY podra
unirse directamente a su campo ID. Debido a que la tabla ActividadGrupo tiene una clave
principal de dos campos (lo que es comn en las bases de datos relacionales), la opcin PRIMARY
KEY est especificada como una entrada propia, con los campos de clave especificados como listas
delimitadas por comas encerradas entre parntesis.
En pginas anteriores de este captulo mostr cmo podra establecerse una referencia a un cap-
tulo en otra tabla empleando las restricciones REFERENCES como parte de la instruccin CREATE
TABLE. Tambin puede establecerlas despus de que ya se han creado las tablas, como hago en
la secuencia de comandos. He aqu la instruccin que establece el vnculo entre las tablas Acti-
vidadGrupo y NombreGrupo:
Proyecto | 123
Como ya he escrito toda la secuencia de comandos de SQL, slo tendr que procesarla directa-
mente empleando Microsoft SQL Server 2005 Management Studio Express. (Si estar usando
la versin completa de SQL Server o alguna otra herramienta de administracin, la secuencia de
comandos proporcionada an funcionar, aunque las instrucciones paso a paso diferirn.) Antes
de agregar las tablas, necesitamos crear una base de datos especfica del Proyecto Biblioteca. Ini-
cie Microsoft SQL Server 2005 Management Studio Express (vase la figura 4-4).
Para agregar una nueva base de datos al Proyecto Biblioteca, haga clic con el botn derecho en
la carpeta Base de datos del Explorador de objetos y seleccione Nueva base de datos del men
contextual. En el formulario Nueva base de datos que aparece, ingrese Biblioteca en el campo
Nombre de la base de datos y luego haga clic en Aceptar.
La base de datos Biblioteca es una envoltura de una base de datos; no contiene tabla ni datos
an. Usaremos el archivo Script de creacin de base de datos.sql del directorio de instalacin del
libro para generar las tablas y los datos iniciales. En Management Studio Express, seleccione el
comando de men Archivo Abrir Archivo, y localice el archivo Script de creacin de base
de datos.sql. (Tal vez se le pida que vuelva a iniciar sesin en SQL Server.) Al abrir este archivo,
se coloca su contenido en un nuevo panel dentro de Management Studio Express.
Figura 4-4. El formulario principal del SQL Server 2005 Management Studio Express.
Figura 4-5. Si no selecciona Biblioteca, sus tablas irn a cualquier otro lado.
Eso es todo! Cierre el panel de secuencia de comandos. Luego regrese al Explorador de objetos,
haga clic con el botn derecho en la carpeta de la base de datos Biblioteca y seleccione Actualizar
del men. Si luego expande la rama de la base de datos Biblioteca y su subrama Tablas, ver todas
las tablas creadas por la secuencias de comandos (vase la figura 4-6).
Con la base de datos hecha, es hora de empezar a programar.
Proyecto | 125
La mera mencin de la palabra ensamblado me transporta a los das en que entr a la prepara-
toria. El ensamblado se tena en realidad en el gimnasio de la escuela, con 2 000 adolescentes
gritones llenando las bancas alrededor de la cancha de basquetbol. Como era una funcin de
la escuela, naturalmente pensaba en una experiencia rica en frescas oportunidades educativas.
Escuela, educacin (las palabras parecen ir juntas). Pero luego vino la banda de msica y los
jugadores de futbol, y las porristas, y la mascota de la escuela (un caballo). Por los siguientes 30
minutos, el director aporre a los estudiantes en un frenes controlado, tratando de probar el
lugar de la institucin como la escuela nmero uno de la ciudad. An no s en qu rea era la
nmero uno, pero resultaba muy estimulante.
Los ensamblados de .NET no son tan estimulantes. En realidad, slo son archivos, EXE y DLL,
y sin que los active, slo estn all sentados, ocupando espacio en disco. Y mientras no estn
haciendo algo ms, tomemos un momento para examinar lo que son y lo que contienen.
Qu es un ensamblado?
Como ya lo mencion en el captulo 1, un ensamblado es una unidad de implementacin,
que en la mayora de los casos es slo un archivo. Un ensamblado es un depsito de cdigo
de aplicacin .NET compilado; cualquier cdigo que escriba con el tiempo se almacenar en
algn archivo EXE (si es una aplicacin) o DLL (para bibliotecas o extensiones de cdigo de
una aplicacin). Todo lo que .NET necesita para cargar y ejecutar su aplicacin se almacena en
el ensamblado.
Los ensamblados son privados o pblicos. Los ensamblados privados estn diseados para usarse
en una sola aplicacin. Si hay algn DLL, un ensamblado EXE es la aplicacin. Los ensamblados
privados aparecen en su propio directorio, el directorio de instalacin de la aplicacin o biblio-
teca. Puede ejecutar dos diferentes ensamblados privados al mismo tiempo y no se molestarn
entre s. Esto es verdadero, aunque cada ensamblado usa la misma combinacin de espacio de
nombre y nombres de clase para sus elementos codificados. Si dos ensamblados de aplicacin
implementan una clase denominada WindowsAplicacin1.Class1, no interferirn entre s
cuando se ejecuten; son privados, y privado significa privado.
126
Qu es un ensamblado? | 127
Vitamina VB 100%
Vitamina C# 0%
* Los valores de porcentaje diarios estn basados
en una Pentium 4 con una memoria de 1 GB.
Sus necesidades diarias pueden ser menores,
pero lo dudo.
Cuando revisa la etiqueta del alimento, sabe lo que contiene el paquete de comida (aunque nadie
sabe en realidad lo que es la riboflavina). Cuando revisa el manifiesto de un ensamblado, sabe de
un vistazo lo que contiene el ensamblado y cules requisitos incluye antes de que pueda cargarse
y ejecutarse.
Aun antes de que .NET entre en escena, los ejecutables y las bibliotecas ya contenan algunos
metadatos, como el nmero de versin del archivo. Pero estos datos no se usaban para admi-
nistrar acceso entre componentes de software, ni estaban organizados de una manera genrica y
extensible. Los metadatos en .NET encarnan todos estos atributos.
La presencia de MSIL y metadatos en cada ensamblado hace que estos archivos sean muy legibles
y comprensibles. Con las herramientas correctas, incluso yo las puedo entender. Y si yo puedo,
cualquiera puede, lo que lleva a un gran problema. Las compaas invierten gran cantidad de
tiempo y dinero en sus esfuerzos de desarrollo de software, y no quieren que cualquier persona
con un poco de ingenio use ingeniera inversa en su cdigo y obtenga todos sus algoritmos se-
cretos. Para evitar esta lectura casual de cualquier aplicacin .NET, Microsoft y otros incluyen
obfuscadores, programas de software que revuelven el contenido de un ensamblado slo suficiente
para que sea difcil de comprender para los seres humanos, pero no para .NET Framework. Ha-
blar ms sobre la obfuscacin en el captulo 22.
Ensamblados y aplicaciones
Las aplicaciones de .NET (archivos EXE) son una instancia de un ensamblado. Pero una sola
aplicacin puede incluir varios ensamblados; en realidad, casi siempre lo hace. Escrib un pe-
queo programa que usa reflejo para presentar todos los ensamblados que est usando el propio
programa. Le di al programa el nombre predeterminado WindowsAplicacin1. Cuando ejecuto
el programa contra s mismo, gener la siguiente lista:
mscorlib
Microsoft.VisualStudio.HostingProcess.Utilities
System.Windows.Forms
System
System.Drawing
Microsoft.VisualStudio.HostingProcess.Utilities.Sync
Microsoft.VisualStudio.Debugger.Runtime
vshost
System.Data
System.Deployment
System.Xml
System.Core
System.Xml.Linq
System.Datos.DataSetExtensions
Microsoft.VisualBasic
WindowsAplicacin1
System.Runtime.Remoting
Necesita una lista de ensamblados, pero le da pereza escribir la palabra Reflection? Pruebe:
My.Aplication.Info.LoadedAssemblies
No hay demasiado en el espacio de nombres My que no pueda hacer con las FCL estndar. In-
cluso hay algunas partes de My que son repeticiones de caractersticas ya incluidas en el lenguaje
Visual Basic, aunque con algunas mejoras. Por ejemplo, Visual Basic incluye un comando Kill
que le permite eliminar archivos. El mtodo My.Computer.FileSystem.DeleteFile tambin
elimina archivos, pero ofrece opciones adicionales, incluida una que le permite enviar el archivo
a la Papelera de reciclaje en lugar de slo perderlo para siempre.
Directivas y ensamblados
Las directivas son como instrucciones de Visual Basic (pero una vez ms, no lo son). Las dos
directivas clave (#Const e #If) proporcionan instrucciones al compilador sobre la manera de
manejar un bloque de cdigo fuente de Visual Basic. (Una tercera directiva, #Region, ayuda
a presentar visualmente el cdigo fuente dentro de Visual Studio, pero no tiene impacto en
el compilador o la aplicacin compilada final.) Mediante el uso de directivas, puede indicar al
compilador que incluya o excluya fragmentos especficos de cdigo fuente del proyecto final. De
modo que en realidad no se trata de instrucciones de cdigo fuente de Visual Basic, pero estn
disponibles en ste.
Por qu querra incluir o excluir cdigo de una aplicacin? Bueno, puedo pensar en varias razo-
nes, algunas de las cuales incluyen a la CIA y al ex director de la Reserva Federal de Estados Uni-
dos, Alan Greenspan. Pero el uso ms comn es cuando quiere producir dos versiones diferentes
de su aplicacin, con base en alguna condicin. Por ejemplo, puede vender una versin exprs
y una profesional de un producto. Gran parte del cdigo es idntico para las dos versiones,
pero la profesional incluira caractersticas no disponibles en la versin exprs. Adems, esta
ltima podra incluir una presentacin simplificada de una caracterstica que tiene un uso ms
complejo en la edicin profesional.
Esto, por supuesto, funciona bien. Pero la aplicacin exprs an contendr todas las caracters-
ticas mejoradas. Como no puede acceder a ninguna parte de ese cdigo, por qu incluirla en la
instalacin del CD? Si usa directivas, puede marcar ese problema como resuelto. Las directivas
usan expresiones condicionales, de manera parecida a la condicin versionProfesional =
True del bloque de cdigo anterior. Pero estn definidos con la instruccin #Const y se les
denomina constantes de compilador.
#Const versionCompleta = True
Esta instruccin define una constante de compilador booleano. La constante slo puede usarse
con directivas; si trata de usar versionCompleta en una instruccin estndar de Visual Basic,
el compilador se quejar. Pero funcionar bien en la directiva #If.
#If (versinCompleta = True) Then
CaracteristasDelShowBis()
#Else
CaracteristicasRisibles()
#End If
Este cdigo se parece mucho al bloque de cdigo anterior, pero con el signo # agregado. Tiene
el mismo aspecto, pero no lo es. Con la instruccin If simple, el siguiente cdigo se compila en
la aplicacin final:
If (versionProfesional = True) Then
CaracteristasDelShowBis()
Else
CaracteristicasRisibles()
End If
Vaya, el bloque completo de cdigo. Pero lo que se incluye con las directivas en la aplicacin
compilada depende del valor de versionCompleta. Si versionCompleta is True, esto se com-
pila en la siguiente aplicacin compilada:
CaracteristasDelShowBis()
Las otras cuatro lneas han desaparecido; se esfumaron en el aire, como si nunca hubieran
existido. Pero en este caso, es algo bueno. El objetivo era tener una versin del ensamblado com-
pletamente dedicada al cdigo no deseado, y es lo que sucedi.
Para establecer la constante de compilador versionCompleta para generar la versin completa,
se incluye esta lnea en la parte superior de cada archivo de cdigo fuente que incluya bloques
de cdigo condicionales #If:
Cuando est listo para generar la versin exprs, slo cambie cada una de estas lneas a su
contraparte False:
#Const versionCompleta = False
De alguna manera, cambiar esta lnea en cada archivo de cdigo fuente que lo necesite parece mucho
trabajo. Y qu pasa si olvido definir en una de ellas la versin correcta? Nada bueno, se lo aseguro.
Para evitar que los desarrolladores en Visual Basic recorran los pasillos gritando ms de lo nor-
mal, Visual Studio proporciona unas cuantas maneras diferentes de establecer constantes de
compilador y hacer que se usen en cada parte de la aplicacin. La manera ms comn de hacerlo
es mediante el panel Compilar, de las propiedades del proyecto (vase la figura 5-3). Haga clic
en el botn Opciones de compilacin avanzadas y luego agregue sus constantes de compilador
global al campo Constantes personalizadas.
Resumen
Los ensamblados no slo son archivos EXE o DLL bien lavados; contienen muchos metadatos,
incluido el manifiesto, que permiten que las aplicaciones de .NET se describan por s solas. El
compilador usa esta informacin para configurar correctamente y procesar el cdigo MSIL ad-
ministrado en cada ensamblado.
Proyecto
En este captulo se da la patada oficial de inicio del proyecto Biblioteca (aplauso). Empezaremos
con algo simple: construir el formulario AcercaDe que proporciona informacin bsica respecto
a la aplicacin, incluido su nmero de versin.
ACCESO AL PROYECTO
Cargue el proyecto Cap05 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap05 (Final) cdigo.
Nuestro objetivo es un formulario placentero que comunique informacin bsica acerca del
programa, un formulario que se parezca al de la figura 5-4.
Como cualquier aplicacin de Visual Basic para Windows, la creacin de este formulario incluye
dos pasos: 1) adicin de controles al formulario, y 2) escritura del cdigo relacionado.
Proyecto | 137
A C
El entorno desplegado incluye cuatro reas clave, que estn etiquetadas con letras en la figura 5-5:
A. El Cuadro de herramientas
Esta lista de controles incluye no slo controles de despliegue, sino tambin controles que
no exponen una interfaz de usuario especfica, como el Timer. (Si no ve el Cuadro de he-
rramientas, seleccione el comando de men Ver Cuadro de herramientas.) Para agregar
un control a un formulario, haga doble clic en el control en el Cuadro de herramientas,
arrstrelo del Cuadro de herramientas al formulario, o dibuje el control en el formulario
despus de seleccionarlo en el Cuadro de herramientas.
B. La superficie del formulario
Coloque aqu cualquier control que exponga una interfaz de usuario. El formulario es WY-
SIWYG, de modo que puede ver el resultado final mientras disea el formulario.
Propiedad Configuracin
(Name) ProgramaAcercaDe
ControlBox False
FormBorderStyle FixedDialog
Size 440, 311
StartPosition CenterScreen
Text Acerca del Proyecto Biblioteca
A continuacin, agregue las ocho etiquetas de texto bsicas a la superficie del formulario, em-
pleando el control Label. Encontrar este control en el Cuadro de herramientas. A medida que
agregue cada control Label, use la lista siguiente de parmetros para establecer las propiedades
de cada etiqueta. El texto incluido coincide con mi situacin, pero sintase con la libertad de
modificar el contenido, como sea necesario.
Proyecto | 139
Agreguemos algunas lneas y secciones coloridas al formulario. Visual Basic 6.0 incluye distintos
controles de forma para lneas, rectngulos y elipses que se podan aplicar directamente a la su-
perficie del formulario. .NET ya no incluye estos elementos; tiene que agregarlos manualmente
empleando comandos de dibujo especificados por cdigo fuente.* Pero podemos simular lneas
y rectngulos usando el control Label estndar, sin el texto.
* Microsoft ofrece controles de lnea y forma como parte de sus Power Packs para Visual Basic 2005. Los encontrar en el rea
de descarga del Microsofts Visual Basic Development Center, localizado en http://msdn.microsoft.com/vbasic. Al momento
de escribir esto, las ediciones 2008 de los Power Packs an no estaban disponibles, pero las versiones 2005 probablemente
funcionarn bien con Visual Basic 2008.
Si la etiqueta FondoLateral oculta la imagen, haga clic con el botn derecho en la etiqueta y
seleccione Enviar al fondo, del men contextual que aparece.
El control LinkLabel es similar al control Label ms bsico, pero puede incluir vnculos en
el texto, secciones en que es posible hacer clic que son similares a los vnculos de una pgina
Web. Los usaremos para desplegar la direccin del sitio Web y de correo electrnico. Agregue
dos controles LinkLabel al formulario y use los siguientes valores para configurar las propiedades
de cada control.
El control final que se agregar es un botn que le permite al usuario cerrar el formulario. Agre-
gue un control Button al formulario con las siguientes propiedades.
Proyecto | 141
Es posible configurar los formularios para que al oprimir la tecla Esc se dispare un control
Button en el formulario, como si el usuario estuviera haciendo clic en el botn en lugar de
oprimir la tecla Esc. Para esto, haga clic en la superficie del formulario y luego establezca la
propiedad CancelButton en AccCerrar. Tenemos que demorar este paso hasta que el botn
se agregue realmente al formulario; la propiedad CancelButton no permitir un valor para un
botn no existente.
Bueno, el formulario debe verse bien por ahora. Lo ltimo que me gusta hacer es configurar el orden
de tabulacin, el orden en que el usuario accede a cada componente del formulario cuando se presio-
na la tecla Tab en el teclado. Para editar el orden de tabulacin, seleccione la superficie del formulario
y luego seleccione el comando de men Ver Orden de tabulacin. Cada control del formulario al
que puede darse un orden de tabulacin de pronto tendr un nmero de orden a un lado. Haga clic
en cada nmero o control en orden hasta que tenga el orden que desea. (Vase la figura 5-6 para co-
nocer cmo orden los controles.) Por ltimo, seleccione de nuevo el comando de men Ver Or-
den de tabulacin una vez ms, o presione la tecla Esc para dejar el proceso de orden de tabulacin.
Tambin puede establecer el orden de tabulacin para cada control al modificar su propiedad
TabIndex, empleando el sistema de nmero basado en cero. Sin embargo, suele ser ms rpido
establecer estos valores al hacer clic en cada control en orden.
Click here
Then here
Double-click here
Proyecto | 143
End Sub
End Class
Cada evento basado en formulario (y, en realidad, casi todos los dems tipos de eventos) en
.NET tienen muchos de los mismos argumentos: (1) un argumento sender que indica cul
objeto dispar este evento, y (2) el argumento e, que permite al sender proporcionar infor-
macin adicional que puede ser til en el evento. En este caso, el argumento sender ser una
referencia al botn AccCerrar, porque es el objeto que generar el evento Click. Un evento
Click del botn no tiene ms informacin til disponible, de modo que e es el tipo de objeto
predeterminado, System.EventArgs, que es muy parecido a un marcador de posicin, y el
objeto del que derivan todos los ms interesantes tipos de argumento de e.
El nombre de este manejador de eventos es AccCerrar_Click, pero si quiere cambiarlo a FerY-
Martha, es correcto; no cambiar nada. Pero debe mantener intacta la clusula Handles Acc-
Cerrar.Click. sta es la parte que vincula al manejador de eventos con el evento real.
El cdigo para cerrar el formulario es extremadamente simple. Ingrselo ahora, ya sea usando el
primer fragmento de cdigo de este captulo o escribindolo directamente.
La lista Nombre de clase aparece a la izquierda. Al seleccionar una entrada de esta lista, se ac-
tualiza la lista de la derecha, Nombre del mtodo. Para agregar una plantilla de manejador de
eventos para el evento LinkClicked de WebEmpresa, primero seleccione WebEmpresa de la
lista Nombre de clase y luego seleccione LinkClicked de la lista Nombre del mtodo. Aparece el
siguiente bloque de cdigo en la ventana de cdigo:
Private Sub WebEmpresa_LinkClicked(ByVal sender As Object, _
ByVal e As System.Windows.Forms. _
LinkLabelLinkClickedEventArgs) _
Handles WebEmpresa.LinkClicked
End Sub
Proyecto | 145
El ltimo evento que se disear es uno de los primeros eventos llamados en el tiempo de vida del
formulario: el evento Load. Se le llama justo antes de que aparezca el formulario en pantalla. Al hacer
doble clic en la superficie del formulario se crea una plantilla de manejador de eventos para el evento
Load. Si prefiere usar, en cambio, las listas Nombre de clase y Nombre del mtodo, seleccione (Pro-
gramaAcercaDe eventos) de la lista Nombre de clase antes de usar la lista Nombre del mtodo.
Private Sub ProgramaAcercaDe_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
End Sub
Agreguemos cdigo a este manejador de eventos que despliegue el nmero de versin correcta,
empleando la informacin de versin encontrada en My.Aplication.Info.Version, una ins-
tancia de la clase System.Version.
Este cdigo usa una instruccin With para reducir la cantidad de escritura necesaria en la ins-
truccin principal de asignacin. Dentro de la instruccin With...End With, no es obligatorio
que vuelva a escribir el nombre del objeto que aparece justo antes de la palabra clave With (en
este caso, My.Aplication.Info.Version). Puede hacer simplemente referencia a los miem-
bros del objeto al escribir un punto (.) seguido por el nombre del miembro. Puede omitir la
instruccin With y escribir el nombre completo del objeto cada vez que quiera usar los valores de
versin, pero de esta manera mantiene su cdigo ms limpio y menos sobrecargado.
Figura 5-10. El formulario Informacin del ensamblado, rellenado con algunos valores relevantes.
Aunque este formulario es conveniente, slo es otro ejemplo de Visual Studio escribiendo el c-
digo de su proyecto por cuenta propia. Cada campo de este formulario se guarda en un archivo
de cdigo fuente incluido en su proyecto. Para verlo, asegrese de que an tiene seleccionado
el botn Mostrar todos los archivos en el Explorador de soluciones. Expanda el elemento My
Proyect usando el signo ms y luego haga doble clic en el elemento AssemblyInfo.vb. Este ar-
chivo define varios asistentes especficos del ensamblado (lo que exploraremos en el captulo 18),
incluidas las siguientes entradas informativas:
<Assembly: AssemblyTitle("El Proyecto Biblioteca")>
<Assembly: AssemblyDescription( _
"ACME Library Base de datos System")>
Proyecto | 147
Como ver, este archivo se ha actualizado con los valores que escrib en el formulario Informa-
cin de ensamblado. Gracias, Visual Studio! Ver el atributo AssemblyVersion definido aqu.
Si modifica estos valores, los cambios se reflejarn en el formulario Informacin de ensamblado,
y tambin en su aplicacin en ejecucin y en el ensamblado compilado final.
Lo ltimo que haremos por ahora al formulario ProgramaAcercaDe es darle un nombre de
archivo con un significado. Actualmente se llama Form1.vb, pero ProgramaAcercaDe.vb sera
mucho ms descriptivo. Para cambiar el nombre, seleccione Form1.vb en el Explorador de so-
luciones, y modifique la propiedad Nombre de archivo a ProgramaAcercaDe.vb en el panel
Propiedades. Si an tiene mostrados todos los archivos, ver que Visual Studio tambin actualiza
los nombres de los dos archivos subordinados del archivo, el archivo del diseador (ProgramaA-
cercaDe.Designer.vb) y el de recursos (ProgramaAcercaDe.resx).
Ahora sera un estupendo momento para que guarde su trabajo (Archivo Guardar todo).
Propiedad Valor
(Name) FormularioPrincipal
FormBorderStyle FixedSingle
MaximizeBox False
Size 576, 459
Text El Proyecto Biblioteca
Del Cuadro de herramientas, agregue un control Button al formulario con las siguientes pro-
piedades:
Propiedad Valor
(Name) AccAyudaAcercaDe
Size 80, 24
Text &Acerca de...
Esa sintaxis an funciona y es la manera que habr de seguir si necesita desplegar varias copias del
mismo formulario en pantalla al mismo tiempo. Sin embargo, la sintaxis ProgramaAcercaDe.
ShowDialog( ) es mucho ms limpia para formularios de un solo uso, y refleja ms de cerca la
manera en que la presentacin del formulario se hizo en Visual Basic desde su versin inicial. En
realidad, esta instruccin est usando el esc My. La instruccin completa tiene este aspecto:
My.Forms.ProgramaAcercaDe.ShowDialog(
)
La coleccin My.Forms le permite hacer referencia a cualquier formato dentro de l sin tener que
decir primero My.Forms. El miembro de la coleccin My.Forms representa instancias predeter-
minadas de cada formulario en el proyecto.
ste es todo el cdigo que necesitamos por ahora, pero si ejecuta el programa, an mostrar
slo el ProgramaAcercaDe. Eso se debe a que este formulario est establecido como formulario
de inicio. Para modificar esto, abra la ventana de propiedades del proyecto, seleccione la ficha
Aplicacin y establezca el campo Formulario de inicio en FormularioPrincipal.
Debido a que el formulario ProgramaAcercaDe se est mostrando ahora como formulario de cua-
dro de dilogo (mediante una llamada a su mtodo ShowDialog), su comportamiento es en cierto
modo diferente. Cada formulario incluye una propiedad DialogResult, cuyo valor es devuelto
por el mtodo ShowDialog cuando se cierra el formulario. Cada botn de su formulario puede
configurarse automticamente para establecer esta propiedad y cerrar el formulario. El botn
Cerrar del formulario ProgramaAcercaDe hace eso; su propiedad DialogResult se establece
en Cancel, que est asignada a la propiedad DialogResult del formulario, cuando el usuario
hace clic en el botn Cerrar. Como efecto lateral, en cualquier momento en que se asigna un
valor (diferente de None) a la propiedad DialogResult del formulario, ste se cierra.
El remate de este prrafo es que ahora puede eliminar el manejador de eventos del evento Click
del botn Cerrar, y el botn an cerrar el formulario. Elimine el procedimiento AccCerrar_
Proyecto | 149
Esto aumenta a tres el nmero de maneras diferentes en que puede cerrar el formulario Progra-
maAcercaDe. Es la flexibilidad de .NET en funcionamiento; hay muchas maneras diferentes de
realizar la misma tarea. Sea creativo!
Guarde su trabajo
Asegrese de que siempre guarda los cambios. Como opcin predeterminada, Visual Studio est
configurado para guardar sus cambios cada vez que se ejecuta su programa, pero prefiero guar-
darlo a menudo slo por si acaso.
En este captulo se incluyeron gran cantidad de instrucciones manuales, porque hay demasiadas
caractersticas estupendas de Visual Studio para jugar con ellas; no pude evitarlo. Probablemente
mantendremos este paso de alguna manera por algunos captulos, pero con el tiempo habr
tanto cdigo que gran parte de l vendr de fragmentos de cdigo.
Datos es una palabra divertida, aunque no tan divertida como datum. Nuestra mente est llena
de datos: las trivialidades tiles e intiles que nublan las ideas; los millones de recuerdos que evi-
tan que las conversaciones superficiales se hagan ms fuertes. Pero la palabra datos rara vez surge
en las conversaciones. A menos que sea un fantico de las computadoras o que se pase todas las
horas del da o la noche en la oficina esperando informes de nmeros procesados, nunca ha te-
nido oportunidad de usar el trmino. Nunca se me ha pedido que le preste a alguien una taza de
datos. Mis amigos nunca tratan de juzgar mi salud al preguntar: Cmo estn tus datos? Y casi
nunca la ha odo usada como el nombre de un personaje en programas populares de televisin
de ciencia ficcin.
A pesar de su falta de uso en la conversacin cotidiana, los datos son extremadamente impor-
tantes. En el mundo de la programacin, lo es todo. En este captulo, analizaremos la manera
en que Visual Basic usa y manipula datos dentro de sus aplicaciones, y la manera en que puede
dominar las herramientas que hacen posible esta manipulacin.
151
2,135
Figura 6-1. Los frutos del trabajo del maestro Peralta.
01001100
Figura 6-2. Las posiciones de un nmero binario de 8 bits (8 dgitos).
Para encontrar el valor de este nmero en el sistema decimal, simplemente sume las columnas. Vea-
mos, hay uno de cada uno de los siguientes valores: cuatro, ocho, sesenta y cuatro, y ninguno del
resto; 4 + 8 + 64, es decir, 76. Debido a que ningn dgito binario puede valer nunca ms de 1, la
cuenta es muy simple. Aqu le mostr un ejemplo binario de 8 bits (8 dgitos), que puede manejar
nmeros del 0 al 255, pero puede representar nmeros decimales ms grandes al aadir ms dgitos.
Eso est correcto para valores enteros, pero cmo representa nmeros decimales y fraccionarios?
Qu hay de los nmeros negativos, donde caben en el sistema binario? Y no se trata slo de n-
meros. Mi computadora puede procesar datos de texto, matrices de nmeros, imgenes grficas
y registros de clientes. Cmo se almacenan en forma binaria?
Para manejar miradas de formas de datos, cada computadora incluye una pequea comunidad
de liliputienses que son buenos en matemticas, lenguas y artes. No, espere, creo que eso provie-
ne de una historia que estoy leyendo a mi hijo cuando va a la cama. Oh, s, ahora recuerdo. Las
computadoras implementan tipos de datos para manejar todas las formas de datos diferentes que
deben administrarse. Cada tipo de datos acta como un intrprete entre una coleccin de bits y
una pieza de informacin que un usuario de computadora puede utilizar y comprender mejor.
Todos los tipos de datos almacenan, al final de cuentas, su contenido como bits individuales
de datos, pero difieren en la manera en que se interpretan esos bits. Imagine un tipo de datos
llamado Vitaminas que indica cules vitaminas se incluyeron en un producto alimenticio. En la
figura 6-3 se muestra la manera en que esos 8 bits usados antes podan asignarse e interpretarse
como vitaminas.
Con este tipo de datos, podra asignar valores de vitaminas a alimentos a los que se da segui-
miento en su aplicacin. (sta slo es una muestra de vitaminas; requerira ms bits para manejar
01001100
Figura 6-3. Cargado con vitaminas B6, D y E.
todas. Este ejemplo no debe usarse como un ofrecimiento de servicios de salud. Consulte a su
mdico.)
Para conocer un ejemplo que est ms a tono con Visual Basic, tome ese nmero 76 que est-
bamos analizando antes. Es lo bastante fcil convertirlo en una representacin binaria, como
01001100. .NET Framework incluye unos cuantos tipos de datos que hacen automticamente
esta conversin, variando slo en el nmero de dgitos binarios (bits) que pueden manejar. En
el mundo de la computacin, 76 tambin representa una letra del alfabeto (la letra L mayscu-
la). Eso se debe a que hay tipos de datos que establece un diccionario entre valores binarios y
caracteres alfabticos (y de otros tipos). Los programas de Windows han usado desde hace mu-
cho ASCII (cdigo estadounidense estndar para intercambio internacional, American Standard
Code for Information Interchange) como diccionario de nmeros a caracteres. Este sistema de 8
bits documenta la manera de convertir los nmeros del 0 al 255 en todos los diversos caracteres
usados en el ingls, incluidos los signos de puntuacin y otros caracteres varios. Otro dicciona-
rio, Unicode, usa 16 bits de datos para manejar alrededor de 65000 caracteres diferentes. .NET
usa Unicode para sus tipos de datos de carcter y de cadena.
Otro tipo de datos que sigue la regla es el booleano, que usa un solo bit para representar True (un
valor de bit de 1) o False (0). Los enteros negativos, los valores decimales de punto flotante y las
fechas y horas completan los tipos de datos bsicos que se usan con ms frecuencia en los equipos
de cmputo y sus aplicaciones. Las estructuras de datos ms complejas pueden construirse a partir de
estos tipos bsicos.
Datos en .NET
Todos los tipos de datos en .NET se implementan como clases dentro del espacio de nombres
System. Uno de esos tipos de datos es System.Byte, que implementa un valor entero de 8 bits,
tal como lo analizamos antes. Contiene valores enteros de 0 a 255. Estos valores se almacenan
siempre empleando datos binarios de 8 bits, pero aparecen mgicamente en forma decimal cada
vez que pida que se presenten.
.NET Framework incluye 15 tipos de datos centrales para interpretacin: 8 para enteros, 3 para
nmeros decimales, 2 para datos de carcter, un tipo de datos combinados para fechas y horas,
y un tipo de datos booleano.
Al revisar estos tipos de otra manera, en la tabla 6-2 se muestra la relacin entre los tipos y su
nmero de bits y estilo rango.
Tabla 6-2. Bits y estado de signo para tipos de datos enteros de .NET.
Tabla 6-3. Una lista exacta de los tipos de datos decimales inexactos.
La clase System.Object
Ya saba que .NET es un entorno de desarrollo orientado a objetos. Lo que probablemente no sabe
es que algunos bromistas de Microsoft hicieron una apuesta para ver si podan hacer que todo el
sistema .NET fuera una sola y enorme clase derivada. Bueno, el grupo que dijo que se poda gan
la apuesta. Todo en .NET (todo el cdigo y todos los datos) se derivan de una sola clase de base:
System.Object. Por s sola, esta clase no tiene muchas caractersticas. Puede decir su nombre, su
tipo y si dos instancias de un objeto son en realidad el mismo objeto. Aparte de eso, no es til para
muchas cosas, excepto para usarse como punto de partida para todas las dems clases y tipos.
Debido a que todas las clases en .NET (incluidos todos los tipos de datos) derivan de System.
Object, puede tratar una instancia de cualquier clase (o tipo de datos) como Object. Los datos
recordarn de qu tipo realmente es, de modo que si tiene System.Int32 pasando como Sys-
tem.Object, puede regresarlo despus a System.Int32.
Todos los tipos de datos de Visual Basic son plenamente intercambiables con sus equivalentes
de .NET. Cualquier instancia de System.Int32 puede tratarse como si fuera una instancia de
Integer, y viceversa.
Literales
La manera ms rpida de incluir valores de un tipo de datos en particular en su cdigo de Visual
Basic es mediante el uso de una literal. Ya ha visto las literales en accin en este libro. En el cap-
tulo 1 se incluy una literal en su proyecto de ejemplo.
MsgBox("Hola, mundo!")
Esta llamada a la funcin MsgBox incluye una literal de cadena. Estas literales siempre aparecen
dentro de un conjunto de comillas. Casi todas las literales numricas aparecen con un carcter
que define un tipo de datos al final de la literal, pero hay otras variantes. En la tabla 6-6 se pre-
senta una lista de los diferentes valores de literales que puede incluir en su cdigo.
Literales | 159
Constantes
Las literales son agradables, pero no siempre queda claro lo que significan. Encontrar el nmero
12 en una frmula, por ejemplo, podra causar que sta generara resultados correctos, pero an
sera til saber lo que significa 12. Es el nmero de meses en un ao, el nmero de horas en un
da, el nmero mnimo de dientes en la boca para comer un bistec, o algo an ms siniestro?
Las constantes proporcionan una manera de asignar nombres con sentido a valores de literal. Se
les trata en gran medida como a stos, pero una vez definidos pueden usarse una y otra vez en su
cdigo. Cada uso de un valor de literal, aunque sea el mismo valor, representa una definicin y
una instancia distintas de ese valor.
En Visual Basic, las constantes se definen usando la palabra clave Const.
Const MesesAnuales As Short = 12
Esta definicin de constante tiene las siguientes partes:
Un nivel de acceso
La definicin de MesesAnuales presentada aqu representa el formato tpico de una defini-
cin de constante incluida dentro de un procedimiento de cdigo. Tambin puede definir las
constantes fuera de los procedimientos, pero an dentro de una clase u otro tipo. Cuando hace
esto, por lo general agrega una palabra clave de modificador de acceso justo antes de la palabra
clave Const. Esta palabra clave indica cunto cdigo podr usar la constante. Describir los
modificadores de acceso un poco ms adelante, en la seccin sobre variables. Las constantes
definidas dentro de un procedimiento slo pueden usarse dentro de ese procedimiento.
Una vez que define una constante, puede usarla de cualquier manera en que usara un equiva-
lente literal.
Const GranSaludo As String = "Hola, mundo."
...Adelante...
MsgBox(GranSaludo)
Enumeraciones
Las enumeraciones, uno de los tipos centrales de .NET, le permiten agrupar como un conjunto va-
lores enteros, con nombre y relacionados. Una vez unidos, la enumeracin puede usar como cual-
quier otro tipo de datos; puede crear variables que son instancias especficas de una enumeracin.
Las enumeraciones son una construccin de varias lneas; la primera define el nombre y el tipo
de datos de la enumeracin. Cada miembro de la enumeracin aparece en una lnea separada,
terminando con una lnea End Enum final de cierre.
01 Enum TipoAuto As Integer
02 Sedan = 1
03 Vagoneta = 2
04 Camioneta = 3
05 SUV = 4
Enumeraciones | 161
La lnea de declaracin (lnea 01) incluye la palabra clave Enum, el nombre de la enumeracin
(TipoAuto) y los tipos de datos subyacentes (Integer). La clusula de tipo As es opcional; si
la deja fuera, la enumeracin tiene Integer como opcin predeterminada. Si proporciona un
tipo de datos, debe ser uno de los siguientes: Byte, Integer, Long, SByte, Short, UInteger,
ULong o UShort.
Cada miembro de la enumeracin (lneas 02 a 06) debe incluir por lo menos un nombre de
miembro (como Sedan). Tiene la opcin de asignar un valor numrico a alguno o a todos los
miembros, como he hecho en el ejemplo. Si un miembro carece de asignacin, se establece en
uno ms de los miembros anteriores. Si ninguno de los miembros tiene un valor asignado, al
primero se asigna 0, al siguiente 1, etctera.
Una vez definidos, los miembros de la enumeracin actan como constantes enteras. Cuando
haga referencia a los miembros de una enumeracin en su cdigo, incluya el nombre de la enu-
meracin y del miembro.
TipoAuto.Sedan
No puede usarse la instruccin Enum dentro de un mtodo o procedimiento. En cambio, debe
definir una enumeracin como un miembro de un tipo (clase, estructura o mdulo), o como
su propio tipo independiente, como en una clase. .NET Framework incluye muchas enume-
raciones predefinidas tiles, que estn orientadas para usarse con caractersticas de .NET. Por
ejemplo, la enumeracin System.DayOfWeek incluye miembros de cada da de la semana.
Variables
Las literales son agradables y las constantes y las enumeraciones an ms, pero ninguna de ellas
puede modificarse una vez que inicia su programa. Esto tiende a hacer que sus aplicaciones
sean rgidas e inflexibles. Si todos sus clientes se llaman Fernando y slo colocan pedidos de
$342.34, tal vez no sea una gran limitacin. Pero casi todos los usuarios quieren ms variedad en
su software. Las variables son contenedores con nombre para datos, como las constantes, pero su
contenido puede modificarse mientras se ejecuta una aplicacin. Adems, pueden contener tipos
de valor y de referencia. He aqu la sintaxis bsica para definir una nueva variable:
Dim nombreCliente As String
La palabra clave Dim (que proviene de la palabra dimensin) define una nueva variable; en este
caso, una llamada nombreCliente con un tipo de datos String. Este contenedor con nom-
bre est listo para contener cualquier valor String; asgnele literales de cadena, otras variables
de cadena o el valor de devolucin de funciones que generan cadenas. Debido a que es un tipo de
referencia, tambin puede asignarle Nothing, un valor y una palabra clave especiales de Visual
Basic que significa este tipo de referencia est vaco, realmente vaco.
nombreCliente = Nothing ' Nothing
nombreCliente = "Fernando" ' Literal
nombreCliente = ObtenerNombreCliente(IDCliente) ' Resultado de la funcion
La ltima lnea en ese bloque de cdigo muestra un tipo de referencia (String) asignado al
resultado String de una funcin. Tambin puede asignar una instancia completamente nueva
de una variable de tipo de referencia. Y ser nueva. Es decir, usar la palabra clave New, que dice
Estoy creando una nueva instancia del tipo de datos especfico. Hay unas cuantas variaciones,
pero todas producen los mismos resultados.
' ----- Variacin de una lnea.
Dim unEmpleado As New Empleado
' ----- Otra variacin de una lnea.
Dim unEmpleado As Empleado = New Empleado
Recuerde que esos tipos de referencia son contenedores que incluyen instrucciones para localizar
los datos reales. Cuando surge a la vida por primera vez una variable de referencia, contiene No-
thing. Es decir, el contenedor no incluye instrucciones porque no hay datos relacionados que
se hayan almacenado en algn lugar. Cuando asigna una nueva instancia a una variable de tipo
de referencia, esa instancia se almacena en algn lugar de la memoria y las instrucciones para
localizar esos datos se vuelcan en el contenedor. En el bloque de cdigo anterior, cada uso de
la palabra clave New crea una nueva instancia de datos en algn lugar de la memoria. Luego, la
ubicacin de estos datos se asigna a la variable unEmpleado.
Muchas clases incluyen uno o ms constructores, rutinas de inicializacin que configuran los valores
iniciales de la instancia. Puede llamar a un constructor especfico mediante la clusula New. El tipo
de String incluye constructores que le permiten construir una cadena inicial. Uno de esos construc-
tores especiales le permite crear una nueva cadena que contiene varias copias de un carcter especfico.
La siguiente instruccin asigna una cadena de 25 asteriscos a la variable muchasEstrellas:
Dim muchasEstrellas As New String("*"c, 25)
Variables | 163
Sub MiProcedimiento()
' ----- Aqu va una variable local.
Dim miVariable As Integer
End Sub
End Class
Hay otras variaciones de sintaxis de la instruccin Dim, algunas de las cuales analizar ms ade-
lante en ste y otros captulos.
Este cdigo declara procesarResultado dentro del bloque For...Next. De modo que slo
estar disponible para usarse dentro de ese bloque; cualquier intento de usar procesarResul-
tado fuera del bloque For genera un error inmediato.
El tiempo de vida de una variable en el nivel del procedimiento empieza cuando el cdigo ingresa
por primera vez en ese procedimiento, y termina cuando el cdigo lo deja. Esto es verdad para
las variables en el nivel del procedimiento y del bloque. Esto significa que si asigna a una variable
en el nivel del bloque algn valor antes de salir de ste, an tendr ese valor si vuelve a ingresar
en ese bloque durante la llamada al mismo procedimiento.
En el caso de campos (variables en el nivel de clase), el mbito depende del nivel de acceso usado
cuando se declara la variable. El tiempo de vida de un campo empieza cuando se crea la instancia
de la clase en el cdigo, y termina cuando se destruye la instancia o cuando deja de usarse.
Pero con la inferencia de tipo local, Visual Basic adivinar el tipo de datos por su cuenta cuando
deje fuera la clusula As.
Dim cosa1
Dim cosa2
cosa1 = "Esto es una cadena."
cosa2 = 25
MsgBox(cosa1.GetType.ToString)
MsgBox(cosa2.GetType.ToString)
Cuando ejecute este cdigo, aparecern dos mensajes para indicarle el nombre del tipo fuerte de
cada cosa: System.String y System.Int32, respectivamente. (No se preocupe por GetType,
por ahora. Slo identifica el tipo verdadero de las cosas.) Visual Basic acta como si las primeras
dos lneas tuvieran este aspecto:
Dim cosa1 As String
Dim cosa2 As Integer
Una vez que Visual Basic identifica el tipo de datos para una de sus variables an sin tipo, esa
variable se pega a ese tipo. El siguiente cdigo fallar:
Como el nombre lo implica, la inferencia de tipo local slo funciona con variables locales. Los
campos de clase deben declararse con un tipo de datos especfico. Tambin se aplican otras res-
tricciones. Consulte al proveedor para conocer ms detalles.
Puede activar y desactivar el sistema de inferencia de tipos empleando la instruccin Option
Infer en la parte superior de cada archivo de cdigo fuente.
Option Infer On
Tambin puede establecer esto en todo un proyecto mediante la ficha Compilar de las propie-
dades del proyecto.
La inferencia de tipo existe para dar soporte a las nuevas caractersticas de LINQ analizadas en el
captulo 17. Aunque puede dejar que Visual Basic infiera la mayor parte de las variables o todas,
no es buena idea hacerlo en la prctica. Aunque el compilador es inteligente, no piensa en la
lgica general de su aplicacin y puede tomar diferentes decisiones de asignacin de tipos de las
que tomara usted. Por ejemplo, Visual Basic puede inferir una variable como Integer, mien-
tras que usted planea incluir en ella valores Long grandes ms adelante. Si tiene la oportunidad
de incluir clusulas As que signifiquen algo y sean exactas con sus instrucciones Dim, hgalo.
Porque yo lo digo. Y porque es la manera correcta de hacer las cosas.
Operadores
Visual Basic incluye diversos operadores que le permiten manipular los valores de sus variables.
Ya ha visto el operador de asignacin (=), que le facilita asignar un valor directamente a una
variable. La mayor parte de los dems operadores le permiten construir expresiones que com-
binan diversos valores originales a la manera de frmulas para su posterior asignacin a una
variable. Considere la siguiente instruccin:
areaCuadrado = largo * ancho
Operadores | 167
Operador Descripcin
+ Suma. Suma dos operandos, produciendo un total. Algunos programadores tambin usan este operador para rea-
lizar unin de cadenas, pero es mejor unir cadenas con otro operador (&) especficamente diseado para ese fin.
Sintaxis: operand1 + operand2
Ejemplo: 2 + 3
+ Suma unaria. Asegura que un operando retenga su signo actual, sea positivo o negativo. Debido a que todos
los operandos retienen automticamente su signo, este operador suele ser redundante. Ser tocado de
nuevo cuando analicemos la sobrecarga de operador en el captulo 12.
Sintaxis: +operando
Ejemplo: +5
- Resta. Resta un operando (el segundo) de otro (el primero), y devuelve la diferencia.
Sintaxis: operando1 operando2
Ejemplo: 10 4
- Negacin unaria. Invierte el signo de su operando. Cuando se usa con un nmero de literal, da como resultado un
valor negativo. Cuando se usa con una variable que contiene un valor negativo, produce un resultado positivo.
Sintaxis: operando2
Ejemplo: 34
* Multiplicacin. Multiplica dos operandos y devuelve el producto.
Sintaxis: operando1 * operando2
Ejemplo: 8 * 3
/ Divisin. Divide un operando (el primero) entre otro (el segundo) y devuelve el cociente. Si el segundo operan-
do contiene cero, ocurre un error de divisin entre cero. (Cuando se trabaja con valores Single y Double,
la divisin entre cero en realidad devuelve indicadores especiales de infinito o no es un nmero.)
Sintaxis: operando1 / operando2
Ejemplo: 9 / 3
\ Divisin de entero. Divide un operando (el primero) entre otro (el segundo) y devuelve el cociente, truncan-
do primero cualquier parte decimal de ese resultado. Si el segundo operando contiene cero, ocurre un error
de divisin entre cero. (Revise el comentario presentado en el operador /.)
Sintaxis: operando1 \ operando2
Ejemplo: 9 \ 4
Mod Mdulo. Divide un operando (el primero) entre otro (el segundo) y devuelve el sobrante como un valor
entero. Si el segundo operando contiene cero, ocurre un error de divisin entre cero. (Revise el comentario
presentado en el operador /.)
Sintaxis: operando1 Mod operando2
Ejemplo: 10 Mod 3
^ Exponenciacin. Eleva un operando (el primero) a la potencia de otro (el segundo).
Sintaxis: operando1 ^ operando2
Ejemplo: 2 ^ 8
& Unin de cadenas. Une dos operandos y devuelve un resultado con la cadena combinada. Ambos operandos
se convierten a su equivalente String antes de unirse.
Sintaxis: operando1 & operando2
Ejemplo: "O" & "K"
Operador Descripcin
Y Conjuncin. Realiza una conjuncin lgica o en el nivel de bits sobre dos operandos y devuelve el resultado.
En el caso de operaciones lgicas (booleanas), el resultado ser True slo si ambos operadores se evalan
como True. Para operaciones en el nivel de bits (enteros) cada bit especfico del resultado ser 1 slo si
los bits correspondientes en ambos operandos son 1.
Sintaxis: operando1 Y operando2
Ejemplo: esOficinista Y esCaballero
O Disyuncin. Realiza una conjuncin lgica o en el nivel de bits sobre dos operandos y devuelve el resultado.
En el caso de operaciones lgicas (booleanas), el resultado ser True si cualquier operando se evala como
True. Para operaciones en el nivel de bits (enteros) cada bit especfico del resultado ser 1 slo si el bit
correspondiente en cada operando es 1.
Sintaxis: operando1 O operando2
Ejemplo: disfrutaLasMontanas O enjoySea
AndAlso Conjuncin de corto circuito. Este operador es equivalente a la versin lgica del operador Y, pero si el pri-
mer operando se evala como False, el segundo no se evaluar en absoluto. Este operador no da soporte
a operaciones en el nivel de bits.
Sintaxis: operando1 AndAlso operando2
Ejemplo: esOficinista AndAlso esCaballero
OrElse Disyuncin de corto circuito. Este operador es equivalente a la versin lgica del operador O, pero si el pri-
mer operando se evala como True, el segundo no se evaluar en absoluto. Este operador no da soporte a
operaciones en el nivel de bits.
Sintaxis: operando1 OrElse operando2
Ejemplo: disfrutaLasMontanas OrElse disfrutaElMar
Not Negacin. Realiza una negacin lgica o en el nivel de bits en un solo operando. En el caso de operaciones
lgicas (booleanas) el resultado ser True si el operando se evala como False, y False si el operando
se evala como True. En el caso de operaciones en el nivel de bits (enteros), cada bit especfico del resulta-
do ser 1 si el bit del operando correspondiente es 0, y ser 0 si el bit del operando es 1.
Sintaxis: Not operando1
Ejemplo: Not listoParaEnviar
Xor Exclusin. Realiza un operacin lgica o en el nivel de bit excluyente o sobre dos operandos y devuelve the
result. En el caso de operaciones lgicas (booleanas) el resultado ser True slo si los operandos tienen
diferentes valores lgicos (True o False). En el caso de operaciones en el nivel de bits (enteros), cada bit
especfico del resultado ser 1 slo si los bits correspondientes en los operandos son diferentes.
Sintaxis: operando1 Xor operando2
Ejemplo: platilloDePollo Xor platilloDeRes
<< Desplazamiento a la izquierda. El operador de desplazamiento a la izquierda desplaza los
bits del primer operando a la izquierda en el nmero de posiciones especificado en el segundo operando y
devuelve el resultado. Los bits empujados a la izquierda del resultado se pierden; los bits
agregados en el extremo derecho son siempre 0. Este operador funciona mejor si el primer operando es un
valor entero sin signo.
Sintaxis: operando1 << operando2
Ejemplo: &H25 << 3
Operadores | 169
Operador Descripcin
>> Desplazamiento a la derecha. El operador de desplazamiento a la derecha desplaza los bits
del primer operando a la derecha en el nmero de posiciones especificado en el segundo operando y de-
vuelve el resultado. Los bits empujados a la derecha del resultado se pierden; los bits
agregados a la izquierda son siempre los mismos que el bit que se encontraba originalmente en el extremo
izquierdo. Este operador funciona mejor si el primer operando es un valor entero sin signo.
Sintaxis: operando1 >> operando2
Ejemplo: &H25 >> 2
= Igual a (comparacin). Compara dos operandos y devuelve True si tienen el mismo valor.
Sintaxis: operando1 = operando2
Ejemplo: montoEsperado = montoReal
<> No es igual a. Compara dos operandos y devuelve True si no tienen el mismo valor.
Sintaxis: operando1 <> operando2
Ejemplo: valorInicial <> valorFinal
< Menor que. Compara dos operandos y devuelve True si el primero tiene un valor menor que el segundo.
Cuando se comparan valores de cadenas, el resultado es True si el primer operando aparece primero
cuando se ordenan las cadenas.
Sintaxis: operando1 < operando2
Ejemplo: tasaAumento < tasaInflacion
> Mayor que. Compara dos operandos y devuelve True si el primero tiene un valor mayor que el segundo.
Cuando se comparan valores de cadenas, el resultado es True si el primer operando aparece despus
cuando se ordenan las cadenas.
Sintaxis: operando1 > operando2
Ejemplo: tasaAumento > tasaInflacion
<= Menor que o igual a. Compara dos operandos y devuelve True si el primero es menor o igual al valor del
segundo.
Sintaxis: operando1 <= operando2
Ejemplo: tasaAumento <= tasaInflacion
>= Mayor que o igual a. Compara dos operandos y devuelve True si el primero es mayor o igual al valor del
segundo.
Sintaxis: operando1 >= operando2
Ejemplo: tasaAumento >= tasaInflacion
Like Comparacin de patrones. Compara el primer operando con el patrn especificado en el segundo operando
y devuelve True si hay una coincidencia. El operando del patrn da soporte a algunas opciones bsicas de
comodn y seleccin, y se describe por completo en la documentacin proporcionada con Visual Studio. .NET
tambin incluye una caracterstica llamada expresiones regulares que proporciona una solucin de
comparacin de patrones ms amplia.
Sintaxis: operando1 Like operando2
Ejemplo: idGobierno Like patrnSSN
Operador Descripcin
Is Comparacin de tipos. Compara el primer operando con otro objeto, un tipo de datos, o Nothing y
devuelve True si hay una coincidencia. Documentar este operador de manera ms detallada en pginas
posteriores y en el captulo 8.
Sintaxis: operando1 Is operando2
Ejemplo: unaVariable Is Nothing
IsNot Comparacin de tipo negada. Este operador es un mtodo abreviado para el uso de los operadores Is y
Not juntos. Las siguientes dos expresiones son equivalentes:
primero IsNot segundo
Not (primero Is segundo)
Sintaxis: operando1 IsNot operando2
Ejemplo: algo IsNot algoAdicional
TypeOf Comparacin de instancia. Devuelve el tipo de datos de un valor o variable. El tipo de cada clase o tipo de
datos en .NET se implementa como un objeto, basado en System.Type. El operador TypeOf slo
puede usarse con el operador Is:
Sintaxis: TypeOf operando1 Is typeOperand
Ejemplo: TypeOf unaVariable Is Integer
AddressOf Delega la recuperacin. Devuelve un delegado (descrito en el captulo 8) que representa una instancia
especfica de un procedimiento o mtodo.
Sintaxis: AddressOf metodo1
Ejemplo: AddressOf uno.unMetodo
GetType Recuperacin de tipo. Devuelve el tipo de datos de un valor o variable, de manera parecida al operador
TypeOf. Sin embargo, GetType trabaja como una funcin y no es necesario que se utilice con el
operador Is.
Sintaxis: GetType(operando1)
Ejemplo: GetType(one)
Los operadores de no asignacin usan sus operandos para producir un resultado, pero no ha-
cen que los operandos se modifiquen de alguna manera. El operador de asignacin actualiza el
operando que aparece a su izquierda. Adems del operador de asignacin estndar, Visual Basic
incluye varios operadores que combinan el operador de asignacin con alguno de los otros ope-
radores binarios. En la tabla 6-8 se presenta una lista de estos operadores de asignacin.
Operador Basado en
= Operador de asignacin estndar
+= + (suma)
= (resta)
*= * (multiplicacin)
Operadores | 171
Operador Basado en
/= / (divisin)
\= \ (divisin entera)
^= ^ (exponenciacin)
&= & (unin)
<<= << (desplazamiento a la izquierda)
>>= >> (desplazamiento a la derecha)
Estos operadores de asignacin son mtodos abreviados de los operadores completos. Por ejem-
plo, para sumar 1 a una variable numrica, puede usar cualquiera de estas dos instrucciones:
' ----- Incrementa totalProvisional en 1.
totalProvisional = totalProvisional + 1
Variables estticas
Por lo general, el tiempo de vida de una variable en el nivel del procedimiento local termina
junto con el procedimiento. Pero en ocasiones tal vez quiera que una variable retenga su valor
entre cada llamada al procedimiento. En ocasiones tal vez quiera un milln de dlares, pero no
siempre puede tenerlos. Pero s puede hacer que las variables conserven sus valores si lo desea.
Se les llaman variables estticas. Para declarar una variable esttica, use la palabra clave Static
en lugar de Dim.
Static llevaSeguimiento As Integer = 0
La asignacin de 0 a llevaSeguimiento slo se hace una vez, cuando se crea la instancia del tipo
que contiene esta instruccin. Despus de eso, mantiene cualquier valor asignado a l hasta que la
instancia se destruye. Las variables estticas tambin pueden crearse dentro de procedimientos.
Matrices
Las aplicaciones de software a menudo funcionan con conjuntos de datos relacionados, no slo valo-
res de datos aislados. Visual Basic incluye dos maneras principales de trabajar con esos conjuntos de
datos: colecciones (analizadas en el captulo 16) y matrices. Una matriz asigna una posicin numrica
a cada elemento incluido en el conjunto, empezando con 0 y terminando con uno menos el nmero
de elementos incluido. Una matriz de cinco elementos tiene elementos numerados de 0 a 4.
Como ejemplo, imagine que est desarrollando una aplicacin de simulacin de zoolgico. Po-
dra incluir una matriz llamada animales que incluya cada nombre de animal en su zoolgico:
Cada elemento de una matriz no es tan diferente de una variable independiente. En realidad, po-
dra considerar slo el conjunto de animales en el cdigo de ejemplo que sean variables distintas:
una variable llamada animal(0), otra animal(1), etctera. Pero son mejores que las variables
ordinarias porque puede procesarlas como un conjunto. Por ejemplo, puede rastrear cada ele-
mento empleando un bucle For...Next. Considere una matriz Integer llamada cadaEle-
mento con elementos numerados del 0 al 2. El siguiente bloque de cdigo agrega los elementos
de la matriz como si fueran variables distintas:
Dim montoTotal As Integer
montoTotal = cadaElemento(0) + cadaElemento(1) + cadaElemento(2)
Pero como los elementos estn en una matriz numerada, puede usar un bucle For...Next para
rastrear cada elemento, de uno en uno.
Dim montoTotal As Integer = 0
For contador As Integer = 0 to 2
' ----- Mantener un total actual de los elementos.
montoTotal += cadaElemento(contador)
Next contador
Antes de que asigne valores a elementos de las matrices o que recupere esos elementos, debe decla-
rar y cambiar el tamao de la matriz para sus necesidades. La instruccin Dim crea una matriz como
lo hacen las variables comunes; la instruccin ReDim cambia el tamao de una matriz despus de
que ya existe.
Dim animal(0 To 25) As String ' Matriz de 26 elementos
Dim animalesAdicionales() As String ' Una matriz String indefinida
ReDim animalesAdicionales(0 To 25) ' Ahora tiene elementos
Por lo general, la instruccin ReDim eliminara cualquier dato existente almacenado en cada ele-
mento de la matriz. La adicin de la palabra clave Preserve retiene todos los datos existentes.
Matrices | 173
Cada elemento de la matriz es un objeto independiente al que pueden asignarse datos conforme
se necesite. En este ejemplo, cada elemento es una String, pero puede usar cualquier tipo de
valor o de referencia que desee en la declaracin de la matriz. Si crea una matriz de elementos
Objeto, puede combinar y comparar los datos de la matriz; no es necesario que el elemento 0
contenga el mismo tipo de datos que el 1.
La propia matriz tambin es un objeto independiente (una instancia de clase que administra su con-
junto de elementos contenidos). Si necesita especificar toda la matriz, y no slo uno de sus elemen-
tos (y hay ocasiones en que necesita hacerlo), use su nombre sin parntesis o valores de posicin.
Una matriz puede tener hasta 60 dimensiones diferentes, aunque suele haber mejores maneras
de organizar datos que dividirlos en sus muchas dimensiones.
Lmites de matriz
El lmite inferior de cualquier dimensin de matriz suele ser 0, como lo indica la clusula 0 To x
cuando se define o redimensiona la matriz. En realidad puede dejar fuera la parte 0 To de la
instruccin, y slo incluir el lmite superior.
' ----- Estas dos lineas son equivalentes.
Dim animal(0 To 25) As String
Dim animal(25) As String
Cada una de estas dos instrucciones crea una matriz con 26 elementos, numeradas del 0 al 25.
Hay unos cuantos casos especiales donde se permiten lmites menores a cero, como cuando se
trabaja con matrices generadas en el COM ms antiguo. Pero la sintaxis estndar de declaracio-
nes de Visual Basic no le permite crear matrices con lmites inferiores a cero.
Para determinar los lmites inferior y superior actuales de una dimensin de matriz, use las fun-
ciones LBound y UBound.
MsgBox("El tablero es " & (UBound(tableroGato, 1) + 1) & _
" by " & (UBound(tableroGato, 2) + 1))
Si su matriz incluye una sola dimensin, no tiene que indicar a LBound o UBound cul dimen-
sin quiere revisar.
MsgBox("El elemento superior se ha numerado " & UBound(animal))
Inicializacin de matrices
Una vez que ha declarado los elementos de su matriz, puede almacenar y recuperar elementos
cuando lo necesite. Tambin es posible almacenar elementos en su matriz en el momento de la
declaracin. La lista de nuevos elementos de la matriz aparece en un conjunto de llaves.
Dim cuadrados( ) As Integer = {0, 1, 4, 9, 16, 25}
Debe dejar fuera las especificaciones de lmites superior e inferior cuando crea una matriz de esta
manera. La matriz cuadrados mostrada aqu tendr elementos numerados del 0 al 5.
Esta clase funciona bien, excepto que FechaDespido en realidad no es correcta. Como opcin
predeterminada, se establecer en 1 de enero del ao 1, a la medianoche, y puede usar esa fecha
como su fecha de nunca se despide. Pero qu pasa si su compaa realmente quiere despedir
a alguien en ese momento, hace dos mil aos?
Prefiero la primera sintaxis, con el signo de interrogacin agregado al tipo de datos. Pero cual-
quier instruccin funcionar. Una vez que est declarada, un tipo de valor puede tomar datos
estndar o Nothing.
FechaDespido = Nothing
FechaDespido = #7/18/2008#
If (FechaDespido Is Nothing) Then...
Hay una sintaxis especial cuando define sus propios tipos de valor como posibles nulos, pero
como usa la caracterstica genricos de Visual Basic, esperar a presentarla hasta el captulo 16.
Funciones de conversin
Las funciones de conversin le permiten convertir datos de un tipo de datos de Visual Basic a
otro. No es aplicable a todo, de modo que no puede convertir la cadena hola en un entero y
esperar que funcione. Pero convertir nmeros de un tipo numrico a otro, o convertir nmeros
entre tipos de cadena y numricos, por lo general funciona bien.
Todas estas instrucciones (excepto CType) tienen la misma sintaxis bsica:
dest = CXxxx(origen)
donde origen es el valor que habr de convertirse con CXxxx. No tiene que asignar el resultado
a una variable; puede usarlo en cualquier lugar en que usara un valor de literal o variable similar.
En la tabla 6-9 se presenta una lista de funciones de conversin integradas.
Funcin Descripcin
CBool Convierte un valor a Boolean.
CByte Convierte un valor a Byte.
Funcin Descripcin
CChar Convierte un valor a Char. Si el valor de origen es una cadena, slo el primer carcter se convierte.
CDate Convierte un valor a Date. Si el valor de origen es una cadena, debe estar en un formato vlido de hora o
fecha.
CDbl Convierte un valor a Double.
CDec Convierte un valor a Decimal.
CInt Convierte un valor a Integer.
CLng Convierte un valor a Long.
CObj Convierte un valor a Object. Es til cuando quiere almacenar un tipo de valor como una instancia de
Object.
CSByte Convierte un valor a SByte.
CShort Convierte un valor a Short.
CSng Convierte un valor a Single.
CType Convierte un valor a cualquier tipo, clase o interfaz definido, ya sea en su aplicacin o en FCL. La sintaxis es:
CType(datosOrigen, nuevoTipo)
donde nuevoTipo es un tipo de datos. Por ejemplo:
CType(5, String)
Convierte el 5 Integer en un String. Al igual que con otras funciones de conversin, no puede conver-
tir datos de un tipo a otro, si los tipos son incompatibles, o si no hay conversin disponible que sepa cmo
generar el tipo de destino a partir del tipo de origen. La sobrecarga de operadores, analizada en el captulo
12, proporciona una manera de hacer que la funcin CType convierta entre tipos que de otra manera
seran incompatibles
CUInt Convierte un valor a UInteger.
CULng Convierte un valor a ULong.
CUShort Convierte un valor a UShort.
Funcin Descripcin
DateAdd Suma o resta un valor de fecha u hora a una fecha de inicio. Por ejemplo, puede sumar 12 minutos, o restar
tres aos, de una fecha determinada.
Funcin Descripcin
DateDiff Devuelve la diferencia entre dos valores de fecha u hora. Puede especificar el intervalo, como meses o segundos.
DatePart Devuelve un componente de una fecha u hora, como la hora o el ao.
DateSerial Devuelve una Date integrada a partir de valores especficos de mes, da y ao.
DateString Devuelve la fecha actual como una cadena. Tambin puede establecer la fecha de la computadora local
utilizando esta palabra clave.
DateValue Devuelve la parte de la fecha de un valor combinado de fecha y hora; la parte de la hora se descarta.
Day Devuelve el da a partir de un valor de fecha determinado.
FormatDateTime Forma una fecha u hora determinada como una cadena, empleando un pequeo conjunto de formatos
predefinidos. Esta funcin se incluye para compatibilidad con cdigo antiguo de VBScript.
Hour Devuelve la hora de un valor de hora determinado.
IsDate Indica si los datos proporcionados a esta funcin son una fecha vlida.
Minute Devuelve el minuto de una valor de hora determinado.
Month Devuelve el mes de un valor de fecha determinado.
MonthName Devuelve el nombre de un mes a partir un valor de mes numrico, de 1 a 12.
Now Devuelve la fecha y hora actuales. Equivalente a TimeOfDay.
Second Devuelve los segundos a partir de un valor de hora determinado.
TimeOfDay Devuelve la fecha y hora actuales. Equivalente a Now.
Timer Devuelve el nmero de segundos que han transcurrido desde la medianoche del da actual. Esta funcin se
restablece a 0 cada medianoche.
TimeSerial Devuelve una Date integrada, a partir de valores especficos de hora, minuto y segundo.
TimeString Devuelve la hora actual como una cadena. Tambin puede establecer la hora en la computadora local
empleando esta palabra clave.
TimeValue Devuelve la parte de la hora de un valor combinado de fecha y hora; se descarta la parte de la fecha.
Today Devuelve la fecha actual.
Weekday Devuelve un entero que indica el da de la semana.
WeekdayName Devuelve el nombre de un da de la semana para un da entero de la semana.
Year Devuelve el ao de un valor de fecha determinado.
Las variables creadas como System.DateTime (o Date de Visual Basic) incluyen varias propie-
dades y mtodos que proporcionan caractersticas similares a las funciones que aparecen en la
lista de la tabla 6-10. Por ejemplo, la propiedad Second devuelve el nmero de segundos.
Dim horaJunta As Date
horaJunta = #11/7/2005 8:00:03am#
MsgBox(horaJunta.Second) ' Despliega '3'
MsgBox(Second(horaJunta)) ' Igual despliega '3'
Puede usar funciones intrnsecas de Visual Basic o los mtodos y las propiedades equivalentes de
System.DateTime en su cdigo. Cada tcnica proporciona el mismo resultado.
Funcin Descripcin
Fix Trunca la parte decimal de un nmero, devolviendo slo la parte entera. Similar a la funcin Int.
FormatCurrency Forma un nmero determinado como un valor de moneda, empleando un conjunto pequeo de formatos
predefinidos. Esta funcin se incluye para compatibilidad con cdigo antiguo de VBScript.
FormatNumber Forma un nmero determinado como un nmero general, empleando un conjunto pequeo de formatos
predefinidos. Esta funcin se incluye para compatibilidad con cdigo antiguo de VBScript.
FormatPercent Forma un nmero determinado como un porcentaje, empleando un conjunto pequeo de formatos predefi-
nidos. Esta funcin se incluye para compatibilidad con cdigo antiguo de VBScript.
Hex Forma un nmero como hexadecimal y devuelve su representacin de cadena.
Int Devuelve el nmero entero que es menor o igual al valor proporcionado. Similar a la funcin Fix.
IsNumeric Indica si los datos proporcionados a esta funcin son un nmero vlido.
Oct Forma un nmero como octal y devuelve su representacin de cadena.
Val Extrae el primer nmero vlido de una cadena y lo devuelve.
.NET Framework incluye la clase System.Math, que contiene varios miembros de funcin
relacionados con clculos matemticos. Algunos de stos, como Round, Sin y Log, se imple-
mentaron como funciones intrnsecas en Visual Basic 6.0, pero se han movido del lenguaje a la
clase Math en .NET.
Visual Basic tambin incluye varias funciones usadas para clculos financieros y de contabilidad.
Estas funciones se incluyeron en Visual Basic 6.0. Como no son relevantes para el proyecto
analizado en este libro, slo presentar aqu sus nombres: DDB, FV, IPmt, IRR, MIRR, NPer, NPV,
Pmt, PPmt, PV, Rate, SLN y SYD.
Funciones de cadena
La manipulacin de cadenas es una parte esencial de la programacin en Windows. Las nuevas
caractersticas XML incluidas con .NET son en realidad slo bonitas rutinas de manipulacin de
cadenas, aunque con las complejidades ocultas. Visual Basic incluye muchas funciones diseadas
para manipular cadenas y caracteres. Aparecen en la tabla 6-12.
Funcin Descripcin
Asc, AscW Devuelve el valor ASCII o Unicode numrico de un carcter.
Chr, ChrW Dado un nmero, estas funciones devuelven el carcter ASCII o Unicode correspondiente.
Filter Devuelve una matriz que es un subconjunto de una matriz de origen, pero incluyendo slo los elementos
que coinciden con un patrn.
Format Forma valores de nmero, fecha y hora que usa cdigos de formato predefinidos o personalizados.
GetChar Extrae un solo carcter de una cadena ms larga.
InStr Devuelve la posicin de una subcadena dentro de una cadena ms larga.
InStrRev Devuelve la posicin de una subcadena dentro de una cadena ms larga, buscando del final de la cadena
hacia el principio.
Join Devuelve una cadena construida a partir de una unin de una matriz de cadenas.
LCase Convierte una cadena a su equivalente en minsculas.
Left Devuelve la parte del extremo izquierdo de una cadena.
Len Devuelve la longitud de una cadena.
LSet Alinea a la izquierda una cadena dentro de una cadena de espacios ms grande.
LTrim Elimina espacios a partir del inicio de una cadena.
Mid Extrae una subcadena a partir de la parte media de una cadena ms larga.
Instruccin Mid Modifica un rango de caracteres en una cadena existente con nuevo contenido. sta no es una funcin, sino
una instruccin especial de Visual Basic. Su sintaxis vara considerablemente de la de casi todas las dems
caractersticas de Visual Basic.
Replace Reemplaza ocurrencias de una subcadena con otra subcadena, todo dentro de una cadena ms larga.
Right Devuelve la parte del extremo derecho de una cadena.
RSet Alinea a la derecha una cadena dentro de una cadena de espacios ms larga.
RTrim Elimina espacio del final de una cadena.
Space Genera una cadena que contiene un nmero especificado de caracteres de espacio. Similar a la funcin
StrDup.
Split Divide una cadena en una matriz de subcadenas con base en un delimitador.
Str Convierte un nmero a su representacin de cadena.
StrComp Compara dos cadenas y devuelve un entero que indica su orden.
StrConv Convierte una cadena a un nuevo formato con base en un cdigo de conversin. Algunas de las conversiones
incluyen el cambio de maysculas y minsculas del contenido.
StrDup Genera una cadena que contiene un nmero especificado de un carcter dado. Similar a la funcin Space,
pero funcin con cualquier carcter.
StrReverse Invierte los caracteres de una cadena.
Trim Elimina espacio del principio y el final de una cadena.
UCase Convierte una cadena a su equivalente en maysculas.
Puede usar las funciones intrnsecas de Visual Basic o los mtodos y propiedades equivalentes de
System.String en su cdigo. Cada tcnica proporciona el mismo resultado, aunque los detalles
y las opciones de sintaxis pueden variar.
Otras funciones
Visual Basic incluye varias funciones que se niegan a insertarse en cualquier de las otras catego-
ras. En la tabla 6-13 se documentan esas funciones.
Funcin Descripcin
DirectCast Convierte un valor de un tipo a otro, aunque los tipos de datos de inicio y final deben estar relacionados.
Similar a las funciones TryCast y CType.
ErrorToString Devuelve la representacin de cadena de un cdigo de error. Esto funciona con los cdigos de error del
sistema previamente disponibles en Visual Basic 6.0, aunque estos cdigos an estn disponibles en .NET.
IsArray Indica si los datos proporcionados a esta funcin son una matriz vlida.
IsDBNull Indica si los datos proporcionados a esta funcin son un valor de base de datos NULL.
IsError Indica si los datos proporcionados a esta funcin son una condicin de error.
IsNothing Indica si los datos proporcionados a esta funcin son indefinidos o tienen el valor Nothing.
IsReference Indica si los datos proporcionados a esta funcin son un tipo de referencia o de valor.
QBColor Devuelve un cdigo de color a partir de un conjunto pequeo de colores predefinidos.
RGB Devuelve un cdigo de color integrado a partir de componentes individuales rojo, verde y azul.
SystemTypeName Dado un nombre de tipo de datos de Visual Basic, esta funcin devuelve el nombre de tipo de datos equiva-
lente de .NET.
TryCast Convierte un valor de un tipo de datos a otro, aunque los tipos de datos de inicio y final deben estar relacio-
nados. Similar a las funciones DirectCast y CType.
TypeName Devuelve un nombre de tipo de datos que resume el tipo del contenido proporcionado. La cadena devuelta
es un resumen generalizado, y no necesariamente el nombre del tipo de datos verdadero.
VarType Devuelve un cdigo que indica el tipo de datos general del contenido proporcionado.
Proyecto
Se ve cansado. Por qu no se toma un descanso de cinco minutos y luego se echa un clavado en
el cdigo del proyecto?
Bienvenido una vez ms! En este captulo usaremos las caractersticas de tipo de datos y funcin
sobre las que ya lemos para disear algunas rutinas de soporte generales que se usarn en todo
el programa. Todo este cdigo aparecer en un mdulo de Visual Basic llamado General, alma-
cenado en un archivo de proyecto llamado General.vb.
ACCESO AL PROYECTO
Cargue el proyecto Cap06 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap06 (Final) cdigo.
Todo el cdigo que agregaremos en este captulo aparecer entre estas dos lneas. Recuerde que
los mdulos son como clases y estructuras, pero no puede crear instancias de ellos; todos sus
miembros son compartidos con todas las partes de su cdigo fuente. Esto les permite usarlos en
cualquier lugar de la aplicacin. No necesitamos hacer nada especial para que estn disponibles
para todo el programa, aparte de establecer el nivel de acceso de cada miembro, de acuerdo con
lo necesario.
En primer lugar, agregaremos algunas de las constantes generales usadas en todo el programa
de regreso a Visual Basic 6.0, llamar a stas constantes globales. Pero ahora simplemente son
miembros compartidos del mdulo General. Agregue el siguiente cdigo justo debajo de la
instruccin Module General.
Estas constantes y las enumeraciones se explican por s mismas con base en sus nombres con uso
de maysculas y minsculas de Pascal. UsarVersionDBV se emplear para asegurar que la apli-
cacin coincida con la base de datos que se est usando cuando hay disponibles varias versiones.
Las constantes CoincidenciaPresente y NingunaCoincidencia se utilizarn para bsquedas
de elementos de la biblioteca.
Las dos enumeraciones definen cdigos que especifican el tipo de bsqueda de artculo de la
biblioteca que se realizar (MetodosBusqueda), y los cdigos de seguridad usados para limitar
las caractersticas que un administrador especfico podr realizar en la aplicacin (Seguridad-
Biblioteca).
Es hora de agregar algunos mtodos. El primer mtodo, CentrarTexto, centra una lnea de
texto dentro de un ancho especfico. Por ejemplo, si tuviera la cadena Hola, mundo (12
caracteres de largo) y quisiera centrarla en una lnea con hasta 40 caracteres de largo, necesitara
agregar 14 espacios al principio de la lnea (determinada al restar 12 de 40 y luego dividir el
resultado entre 2). La rutina usa un par de las funciones especficas de cadena de Visual Basic
(como Trim, Left y Len) para manipular y probar los datos, y el operador de divisin de entero
\ para ayudar a calcular el nmero de espacios que se insertar.
Proyecto | 183
textoResultado = Trim(textoOriginal)
If (Len(textoResultado) >= anchoTexto) Then
' ----- Truncar lo necesario.
Return Trim(Left(textoOriginal, anchoTexto))
Else
' ----- Empezar con espacios adicionales.
Return Space((anchoTexto - Len(textoOriginal)) \ 2) & _
textoResultado
End If
End Funcin
La funcin empieza por hacer una copia de la cadena original (textoOriginal), eliminando
cualquier espacio adicional con la funcin Trim. Luego prueba ese resultado para saber si cabr
en la lnea. Si no, recorta los caracteres finales que no cabrn y devuelve el resultado. En el caso
de cadenas que s caben en el ancho de caracteres anchoTexto de una lnea, la funcin agrega el
nmero apropiado de espacios para iniciar la cadena y devuelve el resultado.
En el fragmento de cdigo #2 tambin se agreg una funcin llamada TextoIzquierdaYDerecha.
Funciona de manera muy parecida a CentrarTexto, pero coloca dos cadenas de texto distintas en los
extremos izquierdo y derecho de una lnea de texto. Alguna pregunta? Estupendo. Sigamos adelante.
El fragmento de cdigo #3 agrega una rutina llamada SoloDigitos. Construye una nueva
cadena hecha con los dgitos encontrado en una cadena de origen, textoOriginal. Hace esto
al llamar a la funcin IsNumeric para cada carcter de textoOriginal, de uno en uno. Cada
dgito encontrado se une entonces al final de textoDestino.
vecesTotales = 0
posInicio = 1
Slo para hacerlo ms interesante, us un mtodo diferente para implementar la funcin Obte-
nerSubCadena. Esta funcin devuelve una seccin delimitada de una cadena. Por ejemplo, la
siguiente instruccin obtiene la tercera parte delimitada por comas de cadenaGrande:
cadenaGrande = "abc,def,ghi,jkl,mno"
MsgBox(ObtenerSubCadena(cadenaGrande, ",", 3)) ' Despliega: ghi
Us la funcin Split de Visual Basic para dividir la cadena original (cadenaOriginal) en una
matriz de cadenas ms pequeas (partesCadena), empleando delim como punto de interrup-
cin. Luego regreso un nmero de elemento cualCampo del resultado. Debido a que cualCam-
Proyecto | 185
Si estas funciones le parecen simples, estupendo! Casi todo el cdigo de Visual Basic es ms
difcil que estos ejemplos. Seguro, podra usar partes no familiares de la FCL, o interactuar con
cosas ms complicadas que cadenas y nmeros. Pero la estructura general ser similar. La mayor
parte del cdigo fuente est integrado por instrucciones de asignacin, pruebas usando la ins-
truccin If, bucles a travs de datos que usan una instruccin For...Next o similar, y llamadas
a funcin. Y eso es lo que hicimos en estos mtodos cortos.
William Shakespeare escribi: Todo en el mundo es un formulario, todos los controles y las eti-
quetas son meros jugadores: marcan la entrada a los eventos y la salida a los eventos; y un control
en su hora expone muchas propiedades (de Mientras lo codifica, acto 2.7.0). Aunque .NET
an estaba en versin beta cuando acu estas palabras, se aplican perfectamente a cualquier
aplicacin de Windows Forms que escriba, aun en nuestros das.
La tecnologa de .NET conocida como Windows Forms incluye todas las clases y caractersticas
necesarias para desarrollar aplicaciones estndar de escritorio para Microsoft Windows. En los
primeros das de Windows, ste era el nico tipo de programa que poda escribir para la plata-
forma. Pero ahora slo es uno de muchos tipos de aplicacin, junto con aplicaciones de consola,
aplicaciones Web (Web Forms) aplicaciones y servicios.
187
Toda ventana de aplicacin era claramente una ventana, como todos los botones, los campos
de entrada de texto, las casillas de verificacin y los botones de opcin, los cuadros de lista y
cuadros combinados (con una ventana separada para la parte desplegable). El texto esttico
y las imgenes grficas se dibujan en una superficie de la ventana, y no incorporan las propias
ventanas. Pero ciertamente cientos de ventanas pueden desplegarse a un mismo tiempo.
Procedimientos de ventanas
As como la bomba de mensajes despacha mensajes a distintos procedimientos de ventana, la
rutina WndProc dirige el procesamiento a bloques de cdigo individuales o procedimientos
basados en el tipo de mensaje entrante. He aqu un esquema lgico general (pseudocdigo) que
muestra la estructura de un procedimiento de ventana tpico:
If (el tipo de mensaje es un clic del ratn)
Do cdigo relacionado con el clic del ratn
Else If (el tipo de mensaje es la opresin de una tecla)
Do cdigo relacionado con la opresin de una tecla
Else If (el tipo de mensaje es el cambio de tamao de una ventana)
Do cdigo relacionado con el cambio de tamao de una ventana
Else...
(El pseudocdigo usa sucesivas instrucciones If, pero un procedimiento de ventana real usa con
ms frecuencia un tipo de instruccin Select Case para procesar el mensaje entrante.) As,
el procedimiento de ventana es como una mquina expendedora. Si el cliente oprime el botn
de los refrescos de cola, hace el procesamiento que regresa una lata de refresco de cola. Si el clien-
te oprime el botn de goma de mascar, hace el procesamiento que regresa goma de mascar. Si el
cliente oprime el botn para regresar el dinero, conserva su dinero.
Para cada tipo de mensaje (por lo menos los que el programa quiere manejar) se procesa algn
cdigo relacionado cuando llega un mensaje. Muchacho, eso realmente suena familiar, pero
parece que recuerda lo que son eventos! Esto suena como a los eventos en Visual Basic. Y as
es. An en Visual Basic 1.0, todas las aplicaciones generadas incluan una bomba de mensajes
y procedimientos WndProc para cada ventana, todas ocultas a la vista. La principal tarea de di-
chos procedimientos WndProc era llamar al cdigo de su manejador de eventos de Visual Basic.
Formularios y controles
En .NET, como en versiones ms antiguas de Visual Basic, las ventanas estn agrupadas en
formularios y controles. Pero an son ventanas, construidas con los mismos componentes
centrales. Si no me cree, revise las clases de los diversos formularios y controles de .NET. Tanto
formularios como controles derivan de la clase comn System.Windows.Forms.Control, que
abstrae la funcionalidad central de ventana de Windows.
Algunos de los controles proporcionados con .NET (y tambin con la versin antigua de Visual
Basic) en realidad no implementan elementos de ventana en pantalla. Estos controles (como
Timer) no incluyen la experiencia de interfaz de usuario, pero s proporcionan una experiencia
de programacin que es similar a la de los controles visibles. Presentar una lista de los controles
especficos un poco ms adelante, en este captulo, e indicar cules no son controles de interfaz
de usuario.
Seleccione el tipo de proyecto Windows y luego la plantilla Aplicacin de Windows Forms. Asig-
ne al proyecto cualquier nombre que quiera en el campo Nombre, y luego haga clic en Aceptar.
El nuevo proyecto ya tiene un solo formulario (Form1) listo para usarse. En este punto, Visual
Studio ya ha agregado alrededor de 250 lneas de cdigo fuente a su aplicacin. Si hace clic en
el botn Mostrar todos los archivos, en el panel Explorador de soluciones (descrito en la figura
1-13, del captulo 1) y abre los varios archivos del proyecto, puede ver el cdigo. La parte ms
interesante est en el archivo Form1.Designer.vb file, editado ligeramente aqu:
Partial Class Form1
Inherits System.Windows.Forms.Form
Todo el cdigo que implementa un comportamiento del formulario aparece en la clase Form del
espacio de nombres System.Windows.Forms. El formulario inicial de este proyecto, Form1,
hereda de ese formulario de base, recibiendo toda la funcionalidad y los parmetros predetermi-
nados de Form. Cualquier cambio personalizado en el momento del diseo hecho a la interfaz
de usuario Form1, como la adicin de controles secundarios, se agrega automticamente al
procedimiento InitializeComponent mientras usa Visual Studio. Revise peridicamente la
rutina para ver cmo cambia.
La mayor parte de los programas tendrn varios formularios. Supongo que .NET podra selec-
cionar al azar uno de los formularios para desplegarlo cuando se ejecuta por primera vez un pro-
grama. Esto sera divertido e impredecible. Pero no funciona de esa manera. En cambio, usted
indica el formulario de inicio mediante las propiedades del proyecto, en el campo Formulario
de inicio, de la ficha Aplicacin (vase la figura 7.3). (La ventana de propiedades del proyecto
aparece cuando selecciona el comando de mens Proyecto Propiedades, en Visual Studio,
o cuando hace doble clic en el elemento My Project, en el Explorador de soluciones.)
Figura 7-3. Las opciones de inicio para una aplicacin de Windows Forms.
Cuando una aplicacin de .NET empieza, el marco conceptual llama a un mtodo denominado
Main en algn lugar de su cdigo. Usted indica cul rutina Main de cul formulario se utiliza
mediante el campo Formulario de inicio. Incluye una lista de todos los formularios; slo elija
el que desee. Pero espere, an no ha agregado el mtodo Main a cualquiera de sus formularios?
No hay problema. Visual Basic escribir una rutina Main simple que desplegar el formulario
indicado. Esta rutina Main ad hoc, agregada en tiempo de compilacin, realiza slo el procesa-
miento mnimo para desplegar el formulario.
Si quiere agregar a su formulario una rutina Main personalizada, o alguna otra clase que no sea
de Form en su aplicacin, no hay problema. Si quita la marca del campo Habilitar marco de
trabajo de la aplicacin en el mismo formulario de propiedades, la lista Formulario de inicio
cambia para incluir cualquier clase de su aplicacin con una rutina Main compatible. Pero el
En la tabla 7-1 se presenta una lista de algunas de las propiedades ms interesantes y sus usos.
Propiedad Descripcin
(Name) Es el nombre del formulario, o ms correctamente de la clase que es el formulario. Como opcin
predeterminada, se llama Formx, donde x es algn nmero. Necesita cambiar por algo informativo.
AcceptButton Indica cul control Button ya colocado en el formulario debe dispararse cuando el usuario oprime la tecla Enter.
AutoScroll Si establece este campo en True, el formulario agrega automticamente barras de desplazamiento que
mueven el contenido del formulario si ste es demasiado pequeo para mostrar todo.
BackColor El color de fondo. Usa un color de sistema especfico o general.
Propiedad Descripcin
ShowInTaskbar Especifica si este formulario debe aparecer como un elemento en la barra de tareas del sistema.
Size Indica el tamao actual del formulario mediante las subpropiedades Width y Height.
StartPosition Especifica la manera en que el formulario debe colocarse en la pantalla cuando aparece por primera vez. Se
establece mediante una lista de valores predefinidos, que en realidad se vinculan con una enumeracin.
Tag Puede colocar cualquier tipo de datos que quiera en esta propiedad; est all para su uso.
Text La leyenda que despliega el formulario se define con este campo.
TopMost Si se establece en True, este formulario aparece arriba de los dems, aunque no sea el formulario activo.
TransparencyKey Indica el color que se usar para transparencia cuando el campo Opacity es diferente de 100%.
WindowState Identifica el estado actual de la ventana: normal, maximizado o minimizado.
Slo inclu la mitad de las propiedades disponibles; evidentemente se tiene una gran cantidad de con-
trol sobre el formulario y la manera en que se presenta al usuario. Lo que es realmente interesante es
que muchas de estas propiedades no estn limitadas slo a los formularios. Algunas de ellas provienen
de la clase mutua System.Windows.Forms.Control y tambin aparecen en todos los controles
que usan la misma clase de base. Esto incluye propiedades como Location, BackColor y Text.
Aunque la presentacin del texto desplegado en la leyenda de un formulario y el texto desplegado en
un botn de comando difieren de manera importante, el uso mediante cdigo es idntico.
Form1.Text = "Esto es la leyenda del formulario."
Button1.Text = "Esto es la leyenda del boton."
Aunque puede establecer todas las propiedades de la tabla 7-1 mediante el panel Propiedades,
tambin puede actualizarlas y verlas mediante cdigo. En realidad, si modific cualquiera de
las propiedades en el panel Propiedades, ya las actualiz mediante cdigo fuente, porque Visual
Studio actualiza su cdigo. Prubelo! Establezca las propiedad TopMost del formulario en True,
y luego vea la rutina InitializeComponent del archivo Form1.Designer.vb file. Encontrar las
siguientes nuevas instrucciones cerca de la parte inferior del mtodo:
Me.TopMost = True
S lo que est pensando: Soy un programador, pero mi editor de texto es el que se est divirtiendo
con la programacin. Cundo tendr una oportunidad de modificar las propiedades mediante c-
digo? sta es una pregunta justa. Es muy fcil modificar las propiedades. Slo mencione el objeto
que se modificar, junto con el nombre de la propiedad y su nuevo valor, como hizo Visual Studio
con la propiedad TopMost.
Me.Text = "El Proyecto Biblioteca"
Se accede a los diversos mtodos del formulario de una manera muy parecida. Por ejemplo, el
mtodo Close cierra el formulario:
Me.Close()
End Class
Como recordar de las primeras pginas de este captulo, sta es la parte para el turista de la clase
Form1, la parte que Visual Studio muestra al pblico (usted), y no las partes ocultas ms interesan-
tes (la parte de Form1.Designer.vb). Pero podremos hacer que esta seccin sea interesante de inme-
diato. Agregue un evento Click a la superficie del formulario al seleccionar (Form1 eventos) de la
lista Nombre de clase (arriba y a la izquierda del editor de texto del cdigo), y luego seleccione Click
de la lista desplegable Nombre del mtodo a su derecha, como se muestra en la figura 7-5.
Si ejecuta este cdigo y hace clic en la superficie del formulario, aparece un cuadro de mensaje
con la leyenda del formulario justo antes de que salga de la aplicacin (vase la figura 7-6).
Adicin de controles
Los nuevos formularios son como lienzos en blanco, y como los grandes pintores antes de no-
sotros, tenemos a nuestra disposicin una gran paleta de herramientas de color a nuestra dispo-
sicin. En Visual Studio, esas herramientas estn en la forma de controles, clases de .NET dise-
adas especficamente para usarlas en superficies del formulario. Visual Basic y .NET incluyen
docenas de controles de Windows Forms, y hay an ms disponibles de terceros. Incluso puede
construir sus propios controles, ya sea al derivarlos a partir de clases de control existentes o al
implementarlos por completo desde cero.
El Cuadro de herramientas de Visual Studio incluye todos los controles bsicos que necesita
para construir aplicaciones de software de alta calidad, o incluso de una pattica baja calidad.
Acceda al Cuadro de herramientas, parte del cual aparece en la figura 7-5, mediante el comando
de men Ver Cuadro de herramientas.
Figura 7-7. Cuadro de herramientas de Visual Studio con controles de Windows Forms.
Aunque no hay un lmite razonable para el nmero de controles que puede agregar a un formu-
lario, hay uno sobre la cantidad de informacin que el usuario puede experimentar en un solo
formulario sin una conexin directa al cerebro. No rebase los lmites.
Figura 7-9. Lo que en realidad sucede cuando el usuario hace clic en un botn.
End Sub
Este manejador de eventos recibe dos argumentos de disparo de un evento: una instancia Sys-
tem.Object (sender) y una System.EventArgs (e). Otros manejadores de eventos pue-
den usar un conjunto de argumentos ligeramente diferente, as que cmo sabe cul usar? Cual-
quier evento definido dentro de una clase de control tambin debe indicar el nmero y el tipo
Seguramente, esta definicin se parece mucho al manejador de eventos, y debe parecerlo. La ins-
truccin Event establece un contrato de paso de parmetros entre el control y cualquier cdigo
que quiera que reciba notificaciones de evento. En este caso, el evento Click promete enviar dos
argumentos al manejador de eventos. El primero, sender, es una referencia que hace el evento
a un objeto. En el caso de controles Button, este parmetro recibe una referencia a la propia
instancia Button. El segundo argumento, e, proporciona un mtodo para pasar un objeto com-
pleto de informacin adicional. La clase System.EventArgs no tiene mucha informacin, pero
algunos eventos usan una variacin del segundo argumento, que emplea System.EventArgs
como su clase de base.
Resulta que los argumentos usados por el evento Click son muy comunes entre los diferentes
controles y eventos. En lugar de volver a escribir la lista de argumentos en cada instruccin
Event, el diseador de un control puede definir un delegado, un tipo .NET que define una lista
de argumentos y, para el caso de funciones, un valor de devolucin.
Public Delegate Sub StandardEventDelegate( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Entonces las instrucciones Event pueden usar el delegado definido como un mtodo abreviado
para no escribir la lista completa de parmetros.
Public Event Click As StandardEventDelegate
Si la instruccin Event usa un delegado a una lista completa de argumentos, tiene una concep-
cin firme de cules datos necesita enviar a cualquier manejador de eventos que escuche. Y enva
esos argumentos usando la instruccin RaiseEvent de Visual Basic. Sigamos este proceso para
el control Button. Cuando el usuario hace clic en el botn, la bomba de mensajes encuentra una
manera de obtener un mensaje al procedimiento WndProc para el control Button. Ese control
examina el mensaje, lo ve como un clic del ratn y decide hablar a los manejadores de eventos
sobre l. Luego, desde el interior del cdigo de WndProc, eleva el evento.
RaiseEvent Click(Me, New System.EventArgs)
La palabra clave de Visual Basic Me alude a la propia instancia del control Button. El argumento
e de un control Button no contiene informacin ms all de los campos predeterminados in-
cluidos en una instancia System.EventArgs, as que WndProc slo enva una nueva instancia
vaca. Los controles con otros argumentos de evento hubieran creado primero una instancia, la
hubieran rellenado con los datos relevantes y pasado esa instancia al manejador de eventos.
Si un evento se dispara en una aplicacin, y no hay un manejador de eventos que lo escuche,
hace un sonido? Tal vez no. No es obligatorio que un evento tenga controladores activos escu-
chndolo. Pero cuando queremos escuchar un evento, cmo lo hacemos? La manera estndar
El cdigo del mtodo InitializeComponent crea la instancia del control Button (lnea 07),
modifica sus propiedades para obtener lo que queremos (lneas 09 a 14) y lo adjunta al formu-
lario (lnea 16). Pero hay una lnea adicional que define la variable de tipo de referencia real
Button1 (lnea 04):
Friend WithEvents Button1 As System.Windows.Forms.Button
Habl acerca de los campos en el nivel de la clase en el captulo 6, y Button1 es slo un cam-
po tpico. Pero la palabra clave WithEvents incluida en la instruccin es lo que le hace saber
al control que alguien quiere monitorear las notificaciones de eventos. Ahora, cada vez que se
dispare un evento Button1, sabe que Form1 puede contener manejadores de eventos que estn
mirando y escuchando.
La segunda parte de nuestro proceso de conexin de evento con manejador de dos pasos incluye
la conexin real al manejador. Echemos un vistazo de nuevo a la definicin del manejador de
eventos Click para la instancia Button1:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
End Sub
Es slo un mtodo de clase ordinario, pero con una clusula Handles colgando al final de la de-
finicin. Esta clusula es la que vincula al manejador de eventos con el propio evento Button1.
Click. Puede colocar varios nombres de evento despus de la palabra clave Handles.
End Sub
Otra variacin consiste en hacer que varios manejadores de eventos monitoreen un solo evento,
aunque Visual Basic decida a cul manejador llama primero.
Private Sub PrimerManejador(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
End Sub
End Sub
Hay otra manera de conectar eventos con manejadores de eventos que no incluyen las palabras
clave WithEvents o Handles, y que le permiten controlar el orden de procesamiento de varios
manejadores. Una vez que tenga una instancia de una clase que expone un evento, adjunta un ma-
nejador a uno de sus eventos usando la instruccin AddHandler. La siguiente instruccin vincula
el evento Click de Button1 con un manejador de eventos llamado MiManejador. El mtodo
MiManejador debe tener la lista de argumentos correctos para el evento definido.
AddHandler Button1.Click, AddressOf MiManejador
El mtodo Show despliega un formulario sin modo. Los formularios sin modo pueden accederse in-
dependientemente de los dems formulario en la aplicacin que se ejecuta. Todos los formularios sin
modo pueden activarse en cualquier momento con slo hacer clic en ellos; el formulario en que haga
clic pasar al frente de los dems y recibir el enfoque de entrada. Un programa podra tener uno, dos o
docenas de formularios sin modo abiertos a la vez, y el usuario puede moverse libremente entre ellos.
Los formularios modales toman el control de toda la entrada de la aplicacin, siempre y cuando
aparezcan en la pantalla. A los formularios modales suele denominrseles cuadros de dilogo;
el usuario debe completar un formulario modal y cerrarlo antes de que se acceda a cualquier otro
formulario en la aplicacin. El cuadro de mensaje que aparece cuando usa la funcin MsgBox es
una ventana de dilogo modal comn. El mtodo ShowDialog despliega formularios modal-
mente, y le permite regresar un valor de ese formulario. Los valores devueltos son los miembros
de la enumeracin System.Windows.Forms.DialogResult.
Si considera que los formularios son obras literarias de Alejandro Dumas, los formatos sin modo
seran como Los tres mosqueteros: Todos para uno y uno para todos. Trabajan juntos para dar
soporte a toda la aplicacin. Los formularios modales son como El conde de Montecristo. S, hay
otros formularios/personajes en la aplicacin/ancdota, pero no son nada cuando el conde est
a la vista.
Para desplegar al conde (es decir, un formulario modal), use el mtodo ShowDialog del formu-
lario y, como opcin, capture su valor de devolucin.
Dim elResultado As DialogResult
elResultado = Form2.ShowDialog()
Los cuadros de dilogo modales son tiles para edicin de algunos registros que requieren que
haga clic en el botn Aceptar, cuando se hayan completado los cambios. Digamos que est es-
cribiendo una aplicacin que despliega una lista de libros de Alejandro Dumas. Podra incluir
dos formularios: 1) un formulario principal que despliega la lista de libros; y 2) un formulario
secundario que le permite escribir el nombre de un solo libro. No sera estupendo que pudiera
regresar el nombre del libro (o, tal vez, un nmero de ID de un registro para el libro, tal como
se almacena en una base de datos) en lugar de un valor de DialogResult?
Si el mtodo ShowDialog, un mtodo pblico de la clase Form, puede devolver un cdigo de
resultado, tal vez podemos agregar otro mtodo pblico para un formulario que devolver un c-
digo de resultado que tenga un significado real. Por supuesto, s podemos. Considere el formu-
lario secundario (llamado EntradaLibro) con un campo de entrada de datos (TituloLibro) y
botones Aceptar (AccAceptar) y Cancelar (AccCancelar), como se muestra en la figura 7-10.
Cuando se alimenta con el siguiente cdigo, este simple formulario devuelve cualquier cosa
escrita en el campo cuando el usuario hace clic en Aceptar (rechazando primero los valores en
blanco), o devuelve una cadena en blanco al hacer clic en Cancelar:
Public Class EntradaLibro
Public Funcin EditarLibro() As Cadena
' ----- Mostrar el formulario y devolver lo que ingresa el usuario.
If (Me.ShowDialog() = DialogResult.OK) Then
Return TituloLibro.Text.Trim
Else
Return ""
End If
End Funcin
Para usar este formulario, el formulario principal llama al mtodo EditarLibro, que devuelve
el ttulo del libro ingresado por el usuario.
Dim nuevoTitulo As Cadena = EntradaLibro.EditarLibro(
)
Resumen
La programacin en Windows en realidad no ha cambiado mucho desde Windows 1.0. An
hace todo mediante mensajes, colas de mensajes y procedimientos de ventana. Lo que ha cam-
biado es la manera en que se abstrae el cdigo para beneficio del programador. El paquete de
.NET Framework para desarrollo en Windows, Windows Forms, facilita el desarrollo de aplica-
ciones de escritorio de Windows y (me atrevo a decirlo) lo hace divertido!
Proyecto
El cdigo del proyecto de este captulo implementa el formulario bsico Principal del Proyecto
Biblioteca, adems del formulario Bienvenido que aparece cuando inicia el proyecto. Micro-
soft, sabiendo que sta era una necesidad comn, incluy soporte para formularios principales y
de bienvenida en el sistema de marco conceptual de la aplicacin de Visual Basic. Como opcin
predeterminada, este sistema se habilita mediante el panel Aplicacin de la propiedades del pro-
yecto (vase la figura 7-11).
Figura 7-11. Campos de inicio y presentacin mediante las propiedades del proyecto.
ACCESO AL PROYECTO
Cargue el proyecto Cap07 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap07 (Final) cdigo.
End Class
End Namespace
Proyecto | 213
Ahora ejecute el programa, y ver que la pantalla de bienvenida se queda alrededor de tres segundos
(3000 milisegundos). Aunque es gratificante verla por tanto tiempo, es posible que la base de datos
real y el cdigo de inicializacin de la aplicacin tome mucho menos de tres segundos. Quiero
decir, estamos hablando aqu de SQL Server. Se supone que es resplandecientemente rpido.
De modo que queda claro que an necesitamos demorar el retiro de la pantalla de bienvenida.
Y resulta que el objeto My.Application incluye la propiedad que necesitamos para imponer
una demora. La propiedad MinimumSplashScreenDisplayTime indica el nmero mnimo de
milisegundos que la pantalla de bienvenida debe desplegarse. Lo malo es que tiene que asignarla
en un lugar realmente extrao, por lo menos comparado con los que hemos aprendido de pro-
gramacin en Visual Basic hasta el momento.
Elimine todo el cdigo que agreg del fragmento de cdigo 1, que sera todo el mtodo My
Application_Startup. Luego, en ese espacio vaco, incluya el siguiente cdigo.
Este bloque de cdigo contiene una gran cantidad de cosas sobre las que an no hemos hablado,
y no hablaremos por algunos captulos. Baste con decir que el mtodo OnInitialize es una de
las primeras cosas que suceden en la vida del programa, y que es el lugar donde debe asignarse
MinimumSplashScreenDisplayTime.
Ejecute el programa de nuevo y sintese con profundo respeto mientras atestigua una pantalla de
bienvenida completamente funcional.
Casi todo este cdigo existe para mover las cosas por el despliegue. Por ejemplo, el usuario puede
acceder a diferentes caractersticas del formulario al hacer clic en los conos o etiquetas de texto rela-
cionadas, a lo largo del lado izquierdo del formulario. Cada cono y etiqueta desencadena una de las
siete rutinas comunes que existen para reordenar los muebles. El cono de la parte superior izquierda,
ImgArtBiblioteca, llama a la rutina comn TareaArtBiblioteca cuando se hace clic en l.
Private Sub ImgArtBiblioteca_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles ImgArtBiblioteca.Click
' ----- Modo Articulo Biblioteca.
TareaArtBiblioteca()
End Sub
Proyecto | 215
Mientras cada teclazo proviene del manejador de eventos KeyDown, la instruccin Select Case
lo examina. Cuando se encuentra una entrada Case coincidente, se ejecuta el cdigo dentro del
bloque Case. Al oprimir la tecla F2 se dispara el cdigo en el bloque Case Keys.F2. Keys es
una de las muchas enumeraciones integradas que puede usar en sus aplicaciones .NET. Observe el
cdigo especial para la tecla F4. Permite la combinacin de teclas Alt-F4 para salir de la aplicacin,
que es la combinacin de teclas estndar para salir de los programas existentes de Windows.
Por lo general, todos los teclazos van al control activo, no al formulario. Para habilitar el manejador
de eventos FormularioPrincipal.KeyDown, la propiedad KeyPreview del formulario debe
estar establecida en True. Establezca esta propiedad de regreso al diseador del formulario.
Proyecto | 217
stos son todos los desafos de este captulo. Lo veo en la siguiente pgina.
219
El objeto
La esencia de la programacin orientada a objetos es, por supuesto, el objeto. Un objeto es una
persona, un lugar, una cosa. Espere un minuto, esos son nombres. Un objeto es como un nom-
bre. Los objetos son construcciones de datos y lgica de computadora que simbolizan entidades
reales, como personas, lugares o cosas. Puede tener objetos que representan personas, empleados,
perros, nutrias marinas, casa, archiveros, computadoras, dobles hlices de DNA, galaxias, imge-
nes, documentos de procesamiento de palabras, calculadoras, artculos de oficina, libros, perso-
najes de telenovela, invasores espaciales, rebanadas de pizza, canales majestuosos que se amorti-
zan a s mismos, plantaciones de t madurado, unas cuantas de mis cosas favoritas y arena.
Los objetos proporcionan un software conveniente con el objetivo de describir y administrar los
datos asociados con uno de esos objetos reales. Por ejemplo, si tuviera un conjunto de objeto
que representan DVD en su coleccin de videos caseros, el objeto podra administrar caracters-
ticas del DVD, como su ttulo, los actores que actan, la longitud del video en minutos, si los
DVD estaban daados o rayados, su costo, etc. Si conectara su aplicacin con el reproductor de
DVD-ROM en su sistema, su objeto incluso podra incluir una caracterstica reproducir que
(suponiendo que el DVD est en la unidad) empezaran a reproducir la pelcula, tal vez a partir
de una posicin de inicio o captulo del DVD.
Los objetos funcionan bien porque su capacidad para simular las caractersticas de sus contrapar-
tes reales a travs de medios de desarrollo de software. Hacen esto a travs de los cuatro atributos
clave de los objetos: abstraccin, encapsulamiento, herencia y polimorfismo.
En todo este captulo, el trmino objeto por lo general har referencia a una instancia de algo,
un uso especfico en memoria del elemento definido, una instancia con su propio conjunto de
datos, no slo su definicin o diseo. Clase alude al diseo y cdigo fuente del objeto, que com-
prende la implementacin.
Abstraccin
Una abstraccin indica la vista limitada de un objeto en relacin con un objeto real. Como una
pintura abstracta, un objeto abstracto muestra slo los elementos esenciales del equivalente real
(vase la figura 8-1).
Los objetos no pueden representar perfectamente contrapartes reales. En cambio, implementan
almacenamiento y procesos de datos en esos elementos de la contraparte real que son importantes
para la aplicacin. El software no es lo nico que requiere abstraccin. Su expediente mdico en
el consultorio del doctor es una abstraccin de su salud fsica total. Cuando compra una nueva
casa, el informe del inspector de la casa es una abstraccin de la condicin real de la construccin.
Aunque el termmetro en su patio trasero es una abstraccin, no puede comunicar con exactitud
todas las variaciones menores de temperatura que existen alrededor de la barra de mercurio. En
lugar de eso, recupera toda la informacin que puede, y comunica un solo resultado numrico.
Todas estas herramientas abstractas registran, comunican o actan slo sobre la informacin
esencial que estaban diseadas para administrar. Un objeto de software, de una manera similar,
slo almacena, comunica o acta sobre informacin esencial acerca de su contraparte real. Por
ejemplo, si estuviera diseando un objeto que monitorea la condicin de una construccin,
podra registrar lo siguiente:
Ubicacin y direccin de la construccin.
Material principal de construccin (madera, concreta, vigas de acero, etc.)
Edad (en aos)
Condicin general (a partir de una lista de opciones)
Notas del inspector
Aunque una construccin tambin tendra color, varias puertas y ventanas, y una altura, estos
elementos tal vez no sean importantes para la aplicacin, y por tanto, no seran parte de la
abstraccin. A esos valores que estn contenidos dentro del objeto se les llama propiedades. A
cualquier regla de procesamiento o clculo contenido dentro del objeto que actan sobre las pro-
piedades (u otros datos proporcionados internos o externos) se le conoce como mtodo. Tomados
en conjunto, mtodos y propiedades integran los miembros del objeto.
Herencia
La herencia en .NET no es como la herencia en la vida real; nadie tiene que morir antes de que
funcione. Pero como en la vida real, la herencia define una relacin entre dos objetos diferentes.
De manera especfica, define la manera en que un objeto desciende de otro.
A la clase original en la relacin del objeto se le denomina clase de base. Incluye varios y diversos
miembros de interfaz, adems de detalles internos de implementacin. Una clase derivada se define
empleando la clase de base como punto de partida. Las clases derivadas heredan las caractersticas de
sta. Como opcin predeterminada, cualquier miembro pblicamente expuesto de la clase de base
se vuelve, de manera automtica, un miembro pblicamente expuesto de la clase derivada, incluida
la implementacin. Una clase derivada puede elegir la sobrescritura de uno, alguno o todos esos
miembros, proporcionando sus propios detalles distintivos y suplementarios de implementacin.
A menudo, las clases derivadas proporcionan detalles especficos a un subconjunto de la clase de
base. Por ejemplo, una clase de base que define animales incluira interfaces para el nombre comn,
el nombre de la especie en latn, el nmero de patas y otras propiedades tpicas que pertenecen a
Polimorfismo
Los conceptos introducidos hasta ahora podran implementarse empleando lenguajes estndar
de programacin procedimental. Aunque no puede hacer herencia real en un lenguaje que no
sea de programacin orientada a objetos, como C, puede simularla empleando campos de mar-
ca: si un campo de marca denominado tipo en una estructura parecida a una clase que no es
de programacin orientada a objetos fue establecida en mamfero, podra habilitar el uso de
ciertos campos especficos de mamferos. Hay otras maneras de simular estas caractersticas, y no
sera demasiado difcil.
El polimorfismo es un ave completamente diferente. Su significado es muchas formas. Debido
a que una clase derivada puede tener su propia versin (sobrescrita) de un miembro de una clase
de base, si trata a un objeto mamfero como un animal genrico, podra haber cierta confusin
sobre cul versin de los miembros debe usarse, la versin de animal o la de mamfero. El poli-
morfismo se ocupa de determinar todo esto, en una base ad hoc, mientras su programa se est
ejecutando. El polimorfismo permite que cualquier cdigo de su programa trate una instancia
derivada como si fuera una instancia de base. Esto resulta estupendo para la codificacin. Si tiene
una rutina que trata a los objetos animal, puede pasarle objetos de tipo animal, mamfero o ave,
y funcionar bien. A este tipo de polimorfismo se le conoce como polimorfismo de asignacin de
subtipos, pero a quin le interesa su nombre.
Interfaces e implementacin
El desarrollo de la programacin orientada a objetos diferencia entre la definicin de una clase,
el cdigo escrito para implementar esa clase y el uso resultante en memoria de esa clase como
objeto. Es similar a la manera en que, en un restaurante, diferencia entre un men, el cocinado
de su seleccin y el alimento real que aparece en su mesa:
Eso es casi todo: la palabra clave Class, y un nombre para la clase (Superheroe, en este caso).
Todas las clases residen en un espacio de nombres (analizados ya en el captulo 1). Como opcin
predeterminada, sus clases aparecen en un espacio de nombres que tiene el nombre de su proyec-
to. Puede modificar esto en las propiedades del proyecto (para establecer un espacio de nombres
en el nivel superior de su ensamblado) y con la instruccin Namespace (para indicar espacios de
nombres relativos a partir del espacio de nombres de nivel superior de su ensamblado).
Namespace ChicosBuenos
Class Superheroe
End Class
End Namespace
Miembros de clase
El hecho de llamar a su clase Superheroe no le otorgar poderes especiales si no agrega algn
miembro a la clase. Todos los miembros de clase deben aparecer entre los lmites Class y End
Class, aunque si usa la caracterstica Partial para dividir su clase, puede salpicar los miembros
entre las diferentes partes de la clase de cualquier manera que desee.
Puede incluir 11 tipos diferentes de miembros en sus clases de Visual Basic. Otros libros o do-
cumentos pueden darle una cifra diferente, pero estn equivocados, por lo menos si se organizan
las cosas de la manera como lo hago aqu:
Los campos de variables son rpidos y convenientes para agregarlos a clases, pero en ocasiones
ofrecen poco control. Los campos pblicos pueden modificarse a voluntad, sin limitacin alguna,
aunque desee limitar el rango permitido de un campo. Adems, los campos no funcionan direc-
tamente con todas las caractersticas de Visual Basic, incluidas algunas caractersticas especficas
de LINQ. Cuando surgen problemas como ste, puede usar miembros de propiedad en lugar de
miembros de campos de variables. Presentar las propiedades unos prrafos ms adelante.
Campos de constantes
Las constantes se definen de la misma manera que los campos de variables, pero incluyen
la palabra clave Const. Al igual que con las constantes en el nivel del procedimiento, debe
asignar un valor a la constante de inmediato en el cdigo fuente, empleando literales o
clculos simples sin variables.
Private Const FactorBaseFuerza As Integer = 1
Enumeraciones
Las enumeraciones definen valores enteros relacionados. Una vez definidos puede usarlos en
su cdigo de la misma manera que otros valores enteros.
Private Enum SuperPoderGeneral
Vuelo
Velocidad
SuperVista
SuperOido
RelacionadoConAgua
RelacionadoConTemperatura
HerramientasYObjetos
Disfraces
End Enum
Las enumeraciones tambin pueden definirse en el nivel del espacio de nombres, fuera de
cualquier clase especfica.
Mtodos Sub
Las clases incluyen dos tipos de mtodos: subs y funciones. Todo el cdigo de la lgica de
su aplicacin aparece en uno estos tipos de mtodos o en propiedades, de modo que no se
moleste en buscar cdigo en una enumeracin. Los mtodos sub realizan alguna lgica de-
finida, trabajando de manera opcional en datos pasados como argumentos.
Si usa el estilo de asignacin a nombre de funcin para asignar un valor devuelto, use la
instruccin Exit Function para regresar al cdigo que llama en cualquier momento.
Propiedades
Las propiedades combinan las ideas de campos y mtodos. Puede crear propiedades de
lectura-escritura, slo lectura o slo escritura mediante los accesotes Get y Set. El siguiente
cdigo define una propiedad de slo escritura:
Public WriteOnly Property IdentidadSecreta(
) As Cadena
Set(ByVal valor As Cadena)
VerdaderaIdentidad = valor
End Set
End Property
Delegados
Los delegados definen argumentos y devuelven valores para un mtodo, y los encierran en
un solo objeto independiente. Suelen usarse para dar soporte al proceso del evento, a proce-
dimientos de devolucin de llamada y a llamadas indirectas a mtodos de clase.
Public Delegate Sub LlamadaGenericaAPoder( _
ByVal factorFuerza As Integer)
Como los delegados son muy genricos, suelen definirse en el nivel del espacio de nombres,
fuera de cualquier definicin de clase.
Declaraciones
La instruccin Declare le permite llamar a cdigo definido en archivos DLL externos,
aunque slo funciona con llamadas a DLL de Windows previas a .NET. La sintaxis para
declaraciones se parece mucho a la usada para definir mtodos.
Public Declare Function HablarAChicoMalo Lib "malvado.dll" ( _
ByVal mensaje As Cadena) As Cadena
Una vez definida, una sub o funcin declarada externamente puede usarse en su cdigo
como si fuera una definicin de sub o funcin integrada en .NET. .NET Framework hace
gran parte del trabajo tras bambalinas para intercambiar datos entre su programa y la DLL.
An as, debe tenerse cuidado cuando se interacta con este tipo de cdigo no administra-
do externo, sobre todo si la DLL se llama malvado.dll.
Interfaces
Las interfaces le permiten definir una clase abstracta y, en cierta manera, plantillas de clases.
En una seccin cerca del final de este captulo se analizarn las interfaces. Tambin pueden
definirse en el nivel del espacio de nombres, y suele hacerse.
Tipos anidados
Las clases pueden incluir otras clases (o estructuras) subordinadas para su propio uso interno
o pblico. Si hace pblica una clase secundaria puede devolver instancias de esa clase al
cdigo que usa la clase principal ms grande.
Class Superheroe
Class Superpoder
End Class
End Class
Puede anidar clase a cualquier profundidad, pero no exagere. La creacin de varias clases den-
tro del mismo espacio de nombres probablemente satisfar sus necesidades sin hacer que el c-
digo resulte excesivamente complejo. Pero esa es mi idea; haga lo que quiera. Despus de todo
es su cdigo. Si quiere tirar su vida en una carrera en el cine, no tengo problemas con ello.
La adicin de una estupenda variedad de miembros a una clase es muy divertido. Puede agregar
miembros de clase de cualquier variedad, en cualquier orden y en cualquier cantidad. Si agrega
demasiados miembros, incluso podra obtener un descuento por mayoreo en Visual Studio por
parte de Microsoft, pero no contenga el aliento.
Los miembros compartidos son compartidos literalmente por todas las instancias de su clase
y, si son pblicos, tambin por el cdigo fuera de su clase. Como no requieren una instancia
de un objeto, estn limitados slo a los recursos que no requieren una instancia de objeto. Esto
significa que un mtodo compartido no puede acceder a un campo de variable no compartido
de la misma clase. Cualquier miembro de clase que no est marcado como Shared se conoce
como miembro de instancia.
En lugar de definir dos mtodos distintos, puedo combinarlos en un solo mtodo, y definir un
argumento opcional para el parmetro capas.
Public Overloads Sub PintarCasa(ByVal colorBase As Color, _
Optional ByVal capas As Integer = 1)
La palabra clave Optional puede usarse con cualquier cantidad de parmetros, pero es posible que
los parmetros opcionales aparezcan despus de ellos; los argumentos opcionales siempre deben
ser los ltimos de la lista. Aunque el cdigo que llama no podra pasar un valor para capas, .NET
an requiere que cada parmetro reciba un argumento. Por tanto, cada argumento opcional incluye
un valor predeterminado empleando una asignacin simple dentro de la definicin del parmetro.
El argumento opcional capas usa un valor predeterminado de 1 mediante la clusula = 1.
Herencia
Visual Basic da soporte a la herencia, la unin de dos clases en una relacin ancestro-descendien-
te. Para implementar la herencia, se define la clase de base, y luego se agrega la clase derivada
usando la palabra clave Inherits. Vaya sorpresa!
Class Animal
' ----- Aqui van los miembros de la clase animal.
End Class
Class Mamifero
Inherits Animal
Class Can
Inherits Animal
Public Overrides Sub Sonido()
MsgBox("Guau.")
End Sub
End Class
Cualquier clase que derive de Animal puede proporcionar ahora su propio cdigo personalizado
para el mtodo Sonido. Pero lo mismo es cierto para la clase derivada de Can; la palabra clave
Overridable se pasa a cada generacin. Si necesita detener este atributo en una generacin
especfica, use la palabra clave NotOverridable. Esta palabra clave slo es vlida cuando se
usa en una clase derivada porque los miembros de la clase de base no permiten la sobreescritura,
como opcin predeterminada.
Class Can
Inherits Animal
Public NotOverridable Overrides Sub Sonido(
)
MsgBox(Guau.)
End Sub
End Class
Este cdigo en realidad no parece justo para la clase de base. Quiero decir, defini todos los
requisitos centrales para las clases derivadas, pero no merece crdito porque no puede crearse
directamente una instancia de l. Pero hay una manera para que una clase de base controle su
propio destino y que se lleve toda la gloria. Hace esto con la palabra clave NotInheritable.
NotInheritable Class Animal
End Class
La nica manera de usar una clase NotInheritable consiste en crear una instancia de ella; no
puede usarla como clase de base de otra clase derivada. (Si su clase no heredable contiene miem-
bros compartidos, pueden accederse sin la necesidad de crear una instancia.)
Inherits, MustInherit, NotInheritable, Overrides, Overridable, NotOverridable, ya
no se trata ms del Visual Basic de su abuelita, por cierto. Y an hay una ms de estas inimitables
palabras clave: Shadows. Cuando sobrescribe un miembro de una clase de base, el nuevo cdigo
debe usar una definicin que es idntica a la proporcionada en la clase de base. Es decir, si sobres-
cribe un mtodo de funcin con dos argumentos String y un cdigo de devolucin Integer,
el cdigo que sobrescribe debe usar la misma firma. Los miembros que usan Shadows no tienen
estos requisitos. Un miembro de este tipo coincide con un elemento de la clase de base slo en
el nombre; todo lo dems es distinto. Incluso puede cambiar el tipo del miembro. Si tiene un
mtodo sub llamado ManquillaCacahuate en una clase de base, puede echar sombra sobre ella
en la clase derivada con un campo de variable (o de constante, o una enumeracin o una clase
anidada) tambin llamada ManquillaCacahuate.
Class Alimento
Public Sub ManquillaCacahuate()
End Sub
End Class
Class Antojo
Inherits Alimento
Public Shadows ManquillaCacahuate As String
' Hey, esto ni siquiera es un "Sub"
End Class
Sin la palabra clave Shadows en la clase Antojo, ocurrira un error en tiempo de compilacin.
La instancia puede usar entonces como cualquier otra variable de instancia de .NET. El acceso a
miembros ocurre usando la notacin de punto.
miMascota.Nombre = "Fido"
Tambin puede pasar (dentro de lo razonable) variables de instancia entre sus variaciones de base
y derivadas.
Dim miMascota As Animal
Dim miPerro As Can
miPerro = New Can
miPerro.Nombre = "Fido"
miMascota = miPerro ' Como Can deriva de Animal
MsgBox(miMascota.Nombre) ' Despliega "Fido"
Si Option Strict tiene el valor On habr lmites en su capacidad para convertir entre tipos,
sobre todo en conversiones de estrechamiento (donde los datos de origen no siempre coinciden
con la variable de destino). En estos casos, debe usar la funcin CType (o una de unas cuantas
funciones similares proporcionadas por .NET y Visual Basic) para habilitar la conversin.
miPerro = CType(miMascota, Can)
Para hacer referencia a instancias de clase basta con hacer referencia a la variable u objeto que
contiene la instancia. Esto es cierto para el cdigo que usa una instancia de fuera de la propia
clase. En el caso del cdigo dentro de su clase (como en uno de sus mtodos) se hace referencia
a miembros de su instancia como si fueran variables locales (sin calificacin), o se usa la palabra
clave especial Me.
Class Animal
Public Nombre As String
Public Sub DisplayName()
----- Cualquiera de estas lineas funcionara.
MsgBox(Nombre)
MsgBox(Me.Nombre)
End Sub
End Class
Una palabra clave similar, MyClass, suele actuar como la palabra clave Me, pero tiene cierta
funcionalidad diferente cuando una instancia de clase se almacena en una variable de un tipo
de clase diferente (de base o derivada). Si crea una instancia de Can, pero la almacena en una
variable Animal, las referencia usando Me se concentrarn en el cdigo de Can, mientras que las
referencias a MyClass se concentrarn en el cdigo de Animal. No usar MyClass en el Proyecto
Biblioteca, y en el caso de los usos ms simples de las instancias de clase, nunca la necesitar.
Pero habr ocasiones en que es importante diferenciar entre cdigo de base y derivado, y sa es
la manera como se hace.
Class Can
Inherits Animal
Public Overrides Sub ObtenerLicencia(
)
' ----- Ejecutar codigo de licencia especifico de can, luego...
MyBase.ObtenerLicencia() ' Llama a codigo de la clase Animal
End Sub
End Class
Constructores y destructores
Las instancias de clase tienen un tiempo de vida: un inicio, un tiempo de actividad y, en algn
momento, por suerte, un final. El principio del tiempo de vida de un objeto ocurre mediante un
constructor; sus momentos finales son dictados por un destructor, antes de pasarlo al infinito en
el proceso de recoleccin de basura de .NET.
Cada clase incluye por lo menos un constructor, sea explcito o implcito. Si no proporciona
uno, .NET por lo menos realizar actividades mnimas en el nivel del constructor, como re-
servar espacio de memoria para cada campo de variable de instancia de su clase. Si quiere que
una clase tenga cualquier otra lgica de tiempo de inicio, debe proporcionarla mediante un
constructor explcito.
En Visual Basic los constructores son mtodos sub con el nombre New. Un constructor New sin
argumentos acta como el constructor predeterminado, llamado como opcin predeterminada
cada vez que se necesita una nueva instancia de una clase.
Class Animal
Public Nombre As String
Public Sub New()
' ----- Cada animal debe tener un nombre.
Nombre = "Fulano de tal de la Jungla"
End Sub
End Class
Sin este constructor, las nuevas instancias de Animal no tendran un nombre asignado en el
campo Nombre. Y como las variables String son tipos de referencia, Nombre tendra un valor
inicial de Nothing. No es algo muy amigable para el usuario. Un constructor predeterminado
MsgBox((New Animal(Fido)).Nombre)
' Despliega "Fido"
MsgBox((New Animal(5)).Nombre)
' Despliega "Animal numero 5"
No es tan fcil destruir una instancia de una clase, como podra pensarse. Cuando crea instancias
de la clase local en sus mtodos, en realidad se destruyen cuando se sale del mtodo, si no ha asig-
nado la instancia a una variable fuera del mtodo. Si crea una instancia en un mtodo y la asigna a
un miembro de una clase, vivir en el miembro de la clase por el tiempo de vida de ste, aunque
se haya salido del mtodo que la cre.
Cuando se destruye un objeto, .NET llama a un mtodo especial denominado Finalize, si est
presente, para realizar cualquier limpieza antes de eliminar la instancia de la memoria. Finali-
ze est implementado como un mtodo Protected de la clase de base System.Object; debe
sobrescribir este mtodo en su clase para usarlo.
Class Animal
Protected Overrides Sub Finalize()
' ----- Aqui va el codigo de limpieza. Debe estar seguro
' de llamar al metodo Finalize de la clase de base.
MyBase.Finalize()
End Sub
End Class
Entonces, por qu resulta tan difcil terminar instancias? El problema es que .NET controla la
llamada del mtodo Finalize; es parte del proceso de recoleccin de basura. El marco concep-
tual no limpia continuamente su basura. Es como el servicio de limpia en su casa; la basura es
recogida por el camin slo de vez en cuando. Hasta entonces, se queda all, pudrindose, des-
componindose y sin llamar a su mtodo Finalize. En el caso de la mayor parte de los objetos,
esto no es mucho problema; a quin le importa si la memora para una cadena se libera ahora o
dentro de 30 segundos. Pero hay ocasiones en que es importante liberar los recursos adquiridos
lo ms rpidamente posible. Por ejemplo, si adquiere un candado para un recurso de hardware
externo y slo lo libera con el destructor, podra conservar ese candado mucho despus de que
se sali de la aplicacin. Hablemos de una muerte lenta.
Hay dos maneras de superar este problema. Una consiste en agregar un mtodo de limpieza se-
parado para su clase y esperar que cualquier cdigo que use su clase lo llame. Esto funcionar
hasta que algn cdigo olvide llamar al mtodo. (Por tanto, tambin debe llamar a esta rutina
desde el destructor Finalize). El segundo mtodo es similar, pero usa una interfaz proporcio-
nada por el marco conceptual llamada IDesechable. (Hablar acerca de las interfaces en un
minuto, de modo que no se preocupe por todo el cdigo mostrado aqu.)
Class Animal
Implements IDesechable
Interfaces
Las palabras clave MustOverride y MustInherit fuerzan a las clases derivadas a implementar
miembros especficos de la clase de base. Pero qu pasa si quiere que la clase derivada imple-
mente todos los miembros de la clase de base? Podra usar MustOverride junto a cada mtodo
y propiedad, pero una mejor manera consiste en usar una interfaz. Las interfaces definen cla-
ses abstractas, clases que slo constan de definiciones, sin implementacin. (Los puristas de la
programacin orientada a objetos sealarn que una clase con una sola marca MustOverride
tambin es una clase abstracta. Estupendo.) Las interfaces crean un contrato, un acuerdo que la
clase o estructura que implementa est dispuesta a cumplir.
La instruccin Interface empieza el proceso de definicin de la interfaz. Por convencin, to-
dos los nombres de interfaz empiezan con la I mayscula.
Interface IEdificio
Function AreaPiso() As Double
Sub ModificarExterior()
End Interface
Como se observa aqu, la sintaxis es una versin un poco simplificada de la sintaxis de definicin
de una clase. Todos los miembros de la interfaz se hacen pblicos automticamente, de modo
que no se incluyen modificadores de acceso. Slo se necesita la lnea de definicin de cada miem-
bro porque no hay implementacin. Adems de los mtodos de funcin y sub, los miembros de
la interfaz tambin incluyen propiedades, eventos, otras interfaces y estructuras. Las interfaces
tambin pueden derivar de otras (empleando la palabra clave Inherits), e incluyen automti-
camente todos los miembros de la interfaz de base.
Las clases slo puede heredar de una sola clase de base, pero no hay lmite en el nmero de in-
terfaces que una clase puede implementar.
Class Casa
Implements IEdificio, IDesechable
Adems, un solo miembro de una clase puede implementar varios miembros de una interfaz.
Public Sub PintarCasa() Implements _
IEdificio.ModificarExterior, IContratista.HacerTrabajo
Entonces, por qu usar interfaces? Proporcionan una manera genrica de acceder a fun-
cionalidad comn, incluso entre objetos que no tienen nada en comn. Las clases llamadas
Animal, Casa y Superheroe tal vez no tengan nada en comn en trminos de lgica, pero
podran necesitar una manera consistente de limpiar sus recursos. Si pueden implementar la
interfaz IDesechable, obtienen la capacidad sin la necesidad de derivar de alguna clase de
base.
Mdulos y estructuras
Adems de las clases, Visual Basic proporciona dos caractersticas de definicin de objetos rela-
cionadas: estructuras y mdulos. Aunque tienen nombres diferentes de clase, an actan de
manera parecida a stas, pero con diferentes caractersticas habilitadas e inhabilitadas.
No puede crear una instancia de un mdulo. Al igual que con las clases, los mdulos aparecen
en el contexto de un espacio de nombres. A diferencia de una clase con miembros comparti-
dos, no necesita especificar el nombre del mdulo para usar el miembro del mdulo. Todos los
miembros de mdulos actan como variables y mtodos globales, y pueden usarse de inmediato
en cualquier otro cdigo de su aplicacin sin calificacin adicional. (Puede restringir el uso del
miembro de un mdulo slo al mdulo al declarar el miembro como Private.)
Las estructuras son mucho ms parecidas a las clases que los mdulos. Las clases implementan
tipos de referencia, pero las estructuras implementan tipos de valor. Todas las estructuras derivan
de System.ValueType (que a su vez derivan de System.Object). Por tanto, actan de manera
similar a los tipos de datos centrales de Visual Basic, como Integer. Puede crear instancias de
una estructura usando la misma sintaxis empleada para crear instancias de clase. Sin embargo,
no puede usar una estructura como base para otra estructura derivada. Y aunque puede incluir
un constructor en su estructura, no se da soporte a los destructores.
Debido a la manera en que se almacenan y usan las estructuras en una aplicacin de .NET, son
adecuadas para tipos de datos simples. Puede incluir cualquier nmero de miembros en su es-
tructura, pero es mejor mantener las cosas simples.
Mtodos parciales
Al principio del captulo, escrib acerca de clases parciales, la capacidad de dividir una clase en
varios archivos. Las clases parciales son especialmente comunes en cdigo creado por genera-
dores de cdigo. Visual Studio es, en parte, un generador de cdigo; mientras arrastra y coloca
controles en su formulario, genera cdigo por usted en una clase parcial Form. En estos casos, las
clases parciales tienen dos autores: el generador automatizado y usted.
Los mtodos parciales, nuevos en Visual Basic 2008, tambin son usados por generadores de c-
digo, aunque tiene la libertad de emplearlos por s mismo. Son tiles en especial cuando alguna
Los mtodos parciales siempre deben ser mtodos sub, nunca funciones, y siempre deben de-
clararse como Private. Si proporciona cualquier parmetro, siempre deben decorarse con la
palabra clave ByVal, no ByRef. Hey, muchacho, sas son muchas restricciones.
La mitad implementada tiene un aspecto verdaderamente familiar, excepto por la falta de un
prefijo Partial. Pero es seguro que se ve bien con cdigo real entre las quijadas.
Private Sub ImplementarSiSeAtreve()
MsgBox("Lo hice, como se ve.")
End Sub
En ocasiones, cuando un animal se mueve, tiene efectos colaterales, como espantar a otros ani-
males. Como la segunda mitad del equipo de implementacin, podra programar estos efectos
colaterales al completar la otra mitad del mtodo parcial. Pero si no hubiera efectos colaterales
para esta implementacin en particular, podra simplemente dejar el mtodo parcial sin termi-
nar. Es opcional.
Basta de bla bl. Ve al punto, Tim, dir. El punto es que si nunca escribe la segunda mitad de
un mtodo parcial, el compilador de Visual Basic dejar fuera ambas mitades, generando cdigo
como si la mitad no implementada nunca fuera autogenerada, en primer lugar. As que esa pri-
mera clase Animal se vuelve:
No slo hice que desapareciera la definicin del mtodo parcial, sino que tambin desapareci la
llamada a ese mtodo dentro de la rutina Mover.
Como un programador solitario que escribe cdigo a solas, probablemente nunca crear un
mtodo parcial; el sistema de eventos es una mejor manera de responder de manera genrica a
acciones dentro de una clase. Pero podra tener una posibilidad de escribir el lado de la imple-
mentacin de un mtodo parcial. Los mtodos parciales se usarn en algn cdigo especfico de
LINQ, sobre todo cuando se disea cdigo de LINQ que se comunica con SQL Server. Pero
conocer ms sobre esto en el captulo 17.
Problemas relacionados
Permtame tomar aqu unos cuantos momentos antes de entrar en el cdigo del proyecto para
analizar algunos temas que en realidad no caben en un anlisis particular de las computadoras,
pero que usted podra terminar usando demasiado en sus propias aplicaciones.
El mtodo MsgBox
Aunque lo he usado casi en cada pgina de este libro, hasta hora, nunca le he presentado for-
malmente el mtodo MsgBox. Parte del espacio de nombres Microsoft.VisualBasic, MsgBox
es una continuacin de la funcin MsgBox en la versin original de Visual Basic. Despliega una
ventana simple de mensaje, incluida una seleccin de botones de respuesta y un cono opcional.
Como funcin, devuelve un cdigo que indica en cul botn del formulario hizo clic el usuario,
uno de los valores de enumeracin de MsgBoxResult. La sintaxis es:
Public Function MsgBox(ByVal Prompt As Object, _
Optional ByVal Buttons As MsgBoxStyle = MsgBoxStyle.OKOnly, _
Optional ByVal Title As Object = Nothing) As MsgBoxResult
El parmetro Prompt acepta una cadena para despliegue en el cuerpo principal del cuadro de
dilogo; Buttons indica cules botones, conos y otros parmetros usar cuando se despliega el
cuadro de dilogo; y Title acepta un ttulo de ventana personalizado si quiere que aparezca algo
diferente del ttulo de la aplicacin. La siguiente instruccin despliega la ventana de la figura
8-2:
Dim resultado As MsgBoxResult = MsgBox( _
"Es seguro hacer clic; no va a explotar la computadora.", _
MsgBoxStyle.YesNoCancel O MsgBoxStyle.Question, _
"Haz clic en algo")
La funcin MsgBox se considera una parte intrnseca del lenguaje. Pero como miembro del es-
pacio de nombres Microsoft.VisualBasic, suele usarse dentro del lenguaje Visual Basic. Si
fuera a codificar algo de .NET en C#, normalmente optara por el mtodo MessageBox.Show.
Funciona de manera muy parecida a la funcin MsgBox, pero su segundo y tercer argumentos
estn invertidos. Algunos conformistas de .NET insisten en que MsgBox (y cualquier cosa que
aparezca en el espacio de nombres Microsoft.VisualBasic) debe desdearse en favor de al-
ternativas de biblioteca de clases. Encuentro que es una opcin preferida, pero puede encontrar
que esa persona insiste en que su cdigo es subestndar. Puede leer mis ideas sobre esas tcticas
en el captulo 26.
Si planea desarrollar cdigo de Visual Basic que tenga como destino la plataforma Silverlight de
Microsoft, evitar Microsoft.VisualBasic puede darle mejoras en el rendimiento cuando des-
cargue su ensamblado a la estacin de trabajo del cliente. Las aplicaciones de Silverlight obtienen
grandes beneficios de las reducciones en el tamao del cdigo compilado, al menos para fines de
descarga. Cualquier cosa que pueda hacer para eliminar dependencias de ensamblados externos
como Microsoft.VisualBasic le ayudar a hacer ms rpido su programa.
Uso de DoEvents
Los programas estn diseados para hacer una gran cantidad de cosas, y en ocasiones piensan de-
masiado, y bloquean la computadora. Esto resulta especialmente cierto para mtodos de Visual
Basic que realizan una gran cantidad de transacciones pesadas de base de datos, una tras otra.
El sistema difiere las actualizaciones de pantalla menos importantes de modo que pueda ocurrir
primero ese ms importante procesamiento de datos. Resulta estupendo, pero en ocasiones el
usuario piensa: Esta estpida computadora se muri de nuevo y desconecta el cable. Si tan slo
proporcionara mejorar actualizaciones, el usuario podra ser ms paciente.
Cada control de su formulario (y el propio formulario) incluye un mtodo Refresh, pero puede
ser una molestia actualizar todo de manera constante. Y actualizar la pantalla no hace mucho para
habilitar el botn Cancelar en que quiere que el usuario haga clic para abortar todo ese adora-
ble procesamiento de datos. Para facilitar la vida, Visual Basic incluye un mtodo DoEvents.
Est prevenido de que el abuso de DoEvents puede hacer ms lenta su aplicacin, y puede llevar
a problemas relacionados con llamadas excesivas a un evento. En general, slo debe usarse en un
bloque de cdigo con procesamiento excesivo, y luego debe extenderse para que slo se le llame
unas veces por segundo, cuando mucho.
Argumentos ParamArray
Cualquier mtodo puede habilitar argumentos opcionales, y el cdigo que llama puede elegir
que se incluyan o excluyan esos argumentos. Pero qu pasa si quisiera agregar un nmero ilimi-
tado de argumentos opcionales a un mtodo? Cmo podra escribir, por ejemplo, una funcin
que devuelva el promedio de todos los argumentos proporcionados, sin lmites en el nmero
de argumentos? Aunque podra aceptar cualquier variable de matriz con los valores de datos de
origen, podra usar un argumento de matriz de parmetros, tambin denominado argumento
ParamArray.
Como con los argumentos opcionales, los argumentos ParamArray deben aparecer al final de
una lista de argumentos de mtodos, y slo puede haber una, porque uno es ms que suficiente
para cualquier mtodo. Los argumentos de matriz de parmetros usan la palabra clave Param
Array justo antes del nombre del argumento.
If (origenDatos.GetLength(0) = 0) Then
Return 0@
Else
For Each unValor En origenDatos
totalConstante += unValor
Next unValor
Return totalConstante / origenDatos.GetLength(0)
End If
End Function
Proyecto
El cdigo de este captulo implementa dos caractersticas del Proyecto Biblioteca: 1) una simple
clase auxiliar usada con controles ListBox y ComboBox para administrar texto y datos, y 2) un
conjunto de formularios genricos para editar tablas que permiten la bsqueda en la Biblioteca,
como tablas de cdigos de estado.
En el caso del valor ItemData ms antiguo, el control ListBox incluye una propiedad Value-
Member que identifica el campo o la propiedad del identificador para el objeto de la coleccin
Items. Pero no tiene que usar ValueMember. En cambio, puede simplemente extraer el objeto
en cuestin de la coleccin Items, y examinar sus miembros con su propio cdigo personali-
zado para determinar su identidad. En realidad, es un poco ms de trabajo que con el antiguo
mtodo de Visual Basic 6.0. Pero una vez ms, debido a que puede almacenar objetos de cual-
quier tamao en la coleccin Items, podra optar por almacenar registros de toda una base de
datos, algo que nunca antes poda hacer con .NET.
Proyecto | 245
ACCESO AL PROYECTO
Cargue el proyecto Cap08 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap08 (Final) cdigo.
Pongamos la clase en un archivo propio de cdigo fuente. Agregue un nuevo archivo de clase
mediante el comando de men Proyecto Agregar clase. Asigne al archivo el nombre Da-
tosListaElementos.vb y haga clic en el botn Agregar. El siguiente cdigo aparece automtica-
mente:
Public Class DatosListaElementos
End Class
Esta clase ser muy simple. Slo incluir miembros para el despliegue del texto y el elemento, en
caso de que olvidemos conectar el campo de texto con la propiedad DisplayMember de List-
Box o ComboBox, tambin incluiremos una sobrescritura de la funcin ToString, adems de
un constructor personalizado que facilita la inicializacin de los miembros. Agregue el cdigo
siguiente al cuerpo de la clase.
Ms adelante, cuando sea hora de poblar un ListBox, podemos usar este objeto para agregar el
despliegue y los valores de identificacin.
ListBox1.Items.Add(New DatosListaElementos("Texto del elemento", 25))
La sobrescritura del mtodo Equals nos permite buscar rpidamente elementos ya agregados
a un control ListBox (o similar) usando caractersticas ya incluidas en el control. La colec-
cin Items del control ListBox incluye un mtodo IndexOf que devuelve la posicin de un
elemento coincidente. Por lo general, este mtodo slo coincidir con el propio objeto; si lo
pasa a una instancia de DatosListaElementos, informar si ese elemento ya se encuentra
en el ListBox. El cdigo actualizado de Equals tambin devolver True si pasamos un valor
Integer que coincide con un miembro de DatosListaElementos.DatosElemento para
un elemento que ya se encuentra en la lista.
Dim posicionElemento As Integer = UnListBox.Items.IndexOf(5)
Como todas estas tablas tienen bsicamente el mismo formato (un campo ID, y uno o ms cam-
pos de contenido), debe ser posible disear una plantilla genrica para usarla en edicin de estas
tablas. Un formulario de base (clase) proporcionar las caractersticas de edicin bsicas, que
habrn de desarrollarse por completo mediante versiones derivadas del formulario de base.
Para el proyecto, agregaremos dos formulario, uno de resumen (que despliega una lista de
todos los cdigos definidos actualmente) y uno de detalle (que permite la edicin de un solo
cdigo nuevo o existente). Para simplificar las cosas an ms, incluiremos slo la funcionalidad
ms bsica de administracin de registros en el formulario de resumen, la mayor parte del cdigo
necesario para editar, desplegar y eliminar cdigos aparecer en los formularios de detalle.
Proyecto | 247
Propiedad Valor
(Nombre) FormularioCodigoBase
ControlBox False
FormBorderStyle FixedDialog
ShowInTaskbar False
Size 406, 173
StartPosition CenterScreen
Text Formulario de cdigo
Ahora acceda al cdigo fuente de esta clase (Ver Cdigo). El cdigo nunca crear instancias
de este formulario genrico de manera directa, de modo que deshabilitaremos toda la creacin
directa de instancias al incluir la palabra clave MustInherit.
Public MustInherit Class FormularioCodigoBase
End Class
Las caractersticas principales del formulario sern la adicin de nuevos registros de cdigo, la
edicin de registros de cdigo existentes y la eliminacin de registros existentes. Agregue tres es-
queletos de funcin que den soporte a estas caractersticas. Podramos hacerlas MustOverride,
pero como ver ms adelante, queremos la opcin de mantener la funcionalidad predeterminada
a partir del formulario de base genrico.
El formulario de detalle tambin debe desplegar los ttulos apropiados y la informacin de uso
del formulario de resumen.
Aunque la mayor parte de las tablas proporcionar una corta lista de cdigos alfabetizados, algu-
nas incluirn una gran cantidad (posiblemente miles de cdigos). El formulario de resumen dar
soporte a un mtodo de bsqueda, para localizar rpidamente un cdigo existente. Debido a que
slo ciertos formularios derivados usarn esta caracterstica, no incluiremos MustOverride.
Proyecto | 249
Esto es todo para el formulario genrico. En pginas posteriores de este libro, crearemos versio-
nes derivadas de cada una de las tablas de cdigo.
Vaya a la vista de cdigo fuente del formulario y agregue el fragmento de cdigo justo despus
de la lnea Public Class ListaRegistrosEditados.
La primera lnea del cdigo agregado define una instancia privada del formulario de detalle
genrico que acabamos de disear.
Private EditorDetalle As Biblioteca.FormularioCodigoBase
Este campo contiene una instancia de una clase derivada de FormularioCodigoBase. Esa asig-
nacin aparece en el mtodo pblico AdministrarRegistros.
Public Sub AdministrarRegistros(ByRef UsarDetalle _
As Biblioteca.FormularioCodigoBase)
' ----- Configurar el formulario para uso con este conjunto de codigo.
Dim coincidenciasExcedidas As Boolean
EditorDetalle = UsarDetalle
Proyecto | 251
El cdigo que llama a AdministrarRegistros se pasa en una instancia del formulario, uno de
los formularios derivados de FormularioCodigoBase. Una vez asignado al campo interno Edi-
torDetalle, el cdigo usa las caractersticas pblicas de esa instancia para configurar los elemen-
tos del despliegue en el formulario de resumen. Por ejemplo, la funcin UsuarioPuedeAgregar
del formulario de detalle, que contiene un valor de devolucin Boolean, establece la propiedad
Visible del botn AccAgregar. La llamada al mtodo RellenarListaConRegistros puebla
el control ListBox de resumen con cualquier valor de cdigo existente. Despus de algunos ajus-
tes de despliegue, el mtodo Me.ShowDialog despliega el resumen para el usuario.
Aunque el usuario interacta con los controles en el formulario de resumen, casi todos estos
controles difieren su procesamiento al formulario de detalle, EditorDetalle. Por ejemplo, un
clic en el botn Agregar difiere la mayor parte de la lgica al mtodo AgregarRegistro del
formulario de detalle. El cdigo en el formulario de resumen no hace ms que actualizar sus
propios campos de despliegue.
Private Sub AccAgregar_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles AccAgregar.Click
' ----- Dejar que el usuario agregue un registro.
Dim nuevoID As Integer
Dim nuevaPosicion As Integer
' ----- Preguntar al usuario.
nuevoID = EditorDetalle.AgregarRegistro()
If (nuevoID = -1) Then Return
' ----- Agregar este registro a la lista.
nuevaPosicion = ListaRegistros.Items.Add( _
(New Biblioteca.DatosListaElementos( _
EditorDetalle.FormarNombreRegistro(nuevoID), nuevoID)))
ListaRegistros.SelectedIndex = nuevaPosicion
ActualizarBotones()
ActualizarCuentaElementos(False)
End Sub
Casi todo el resto del cdigo del formulario de resumen es como este (para caractersticas de edi-
cin, eliminacin y bsqueda) o se utiliza para actualizar el despliegue con base en la interaccin
del usuario con el formulario. Asegrese de examinar el cdigo para obtener una buena com-
prensin de la manera en que funciona el cdigo. En captulos posteriores, cuando agreguemos
formularios de detalle reales, veremos este cdigo en accin.
En este captulo cubriremos dos temas importantes de programacin en Visual Basic: expresiones
lambda y manejo de errores. Ambos son misteriosos, porque uno usa una letra griega en su nombre
y el otro porque podra tambin estar en griego por todas las dificultades que los programadores
tienen con l. Las expresiones lambda en particular se relacionan con el concepto ms amplio de
la programacin funcional, la idea de que toda tarea de computacin puede expresarse como una
funcin y que las funciones pueden pasearse por el cdigo fuente. Visual Basic no es un lenguaje
de programacin verdaderamente funcional, pero la introduccin de las expresiones lambda en
Visual Basic 2008 trae algunas de esas maneras y medios funcionales al lenguaje.
Expresiones lambda
Las expresiones lambda se denominan clculos lambda (o clculos-), un sistema matemtico di-
seado en 1930 por Alonzo Church, ciertamente un nombre familiar entre las guerras. Aunque su
trabajo fue muy terico, llev a caractersticas y estructuras que beneficiaron a la mayor parte de
los lenguajes de programacin de hoy en da. De manera especfica, el clculo lambda proporciona
la racionalizacin de las funciones, argumentos y valores de retorno de Visual Basic sobre las que
ya hemos aprendido. As que, por qu agregar una nueva caracterstica a Visual Basic y llamarla
lambda cuando ya hay cosas lamba en el lenguaje? Estupenda pregunta. No hay respuesta.
Las expresiones lambda le permiten definir un objeto que contiene una funcin completa. Aun-
que esto es algo nuevo en Visual Basic, ha existido una caracterstica en el lenguaje BASIC por
largo tiempo. Encontr un antiguo manual del primer lenguaje de programacin que us,
BASIC PLUS en la computadora de tiempo compartido RSTS/E. Proporcionaba un ejemplo
de la instruccin DEF, que permite definir funciones simples. He aqu algn cdigo de ejem-
plo de ese lenguaje que imprime una lista de los primeros cinco cuadrados:
100 DEF SQR(X)=X*X
110 FOR I=1 TO 5
120 PRINT I, SQR(I)
130 NEXT I
140 END
253
Las expresiones lambda en Visual Basic trabajan de manera parecida, dejndole definir una varia-
ble como una funcin simple. He aqu el equivalente de Visual Basic para el cdigo anterior:
Dim cuad As Func(Of Integer, Integer) = _
Function(x As Integer) x * x
For i As Integer = 1 To 5
Console.WriteLnea("{0}{1}{2}", i, vbTab, cuad(i))
Next i
Las expresiones lambda empiezan con la palabra clave Function, seguida por una lista de argu-
mentos pasados entre parntesis. Despus de eso viene la definicin de la propia funcin, una
expresin que usa los argumentos pasados para generar algn resultado final. En este caso, el
resultado es el valor de x multiplicado por s mismo.
Algo que no ve en una expresin lambda es la instruccin Return. En cambio, el valor devuelto
parece salir naturalmente de la expresin. Por eso necesita alguna especie de variable que conten-
ga la definicin y devuelva el resultado en una sintaxis parecida a la de la funcin.
Dim cuad As Func(Of Integer, Integer)
Las variables de la expresin lambda se definen usando la palabra clave Func (qu original). La
lista de argumentos de tipo de datos coincide con la lista de argumentos de la expresin lambda,
pero con un tipo de datos adicional lanzado al final que representa el tipo de datos del valor
devuelto. He aqu una expresin lambda que revisa si un argumento Integer es par o no, de-
volviendo un resultado booleano:
Public Sub ProbarNumero()
Dim EsPar As Func(Of Integer, Boolean) = _
Function(x As Integer) (x Mod 2) = 0
MsgBox("El 5 es par? " & EsPar(5))
End Sub
Este cdigo despliega un mensaje que dice, El 5 es par? False. Tras bambalinas, Visual Basic
est generando una funcin real, y vinculndolo a la variable empleando un delegado. (Un dele-
gado, como tal vez lo recuerde, es una manera de identificar un mtodo genricamente a travs
de una variable distintiva.) El siguiente cdigo est a lo largo de las lneas de lo que el compilador
est realmente generando para el ejemplo de cdigo anterior:
En este cdigo, la expresin lambda y la variable relacionada EsPar se han reemplazado con una
verdadera funcin (FuncionOculta1) y un delegado intermedio (DelegadoOculto1). Aunque
las lambdas son nuevas en Visual Basic 2008, este tipo de funcionalidad equivalente ha estado
disponible desde la primera versin de Visual Basic para .NET. Las expresiones lambda propor-
cionan una sintaxis ms simple cuando la funcin con referencia a delegados slo est regresando
un resultado de una expresin.
Las expresiones lambda se agregaron a Visual Basic 2008, sobre todo, para dar soporte a la nueva
funcionalidad LINQ (consulte el captulo 17). Son especialmente tiles cuando necesita pro-
porcionar una expresin como una regla de procesamiento para algn otro cdigo, sobre todo
cdigo escrito por un tercero. Y en sus propias aplicaciones, Microsoft es un tercero. Coinci-
dencia? No lo creo!
Inclusiones de lambdas
Las expresiones lambda son buenas y todo, pero resulta evidente que la funcionalidad equiva-
lente ya estaba disponible en el lenguaje. Y por s mismas, las expresiones lambda son slo una
simplificacin de alguna compleja sintaxis de funcin-delegado. Pero cuando combina expresio-
nes lambda con el tipo de caractersticas de inferencia de tipo analizadas en el captulo 6, tiene
algo an mejor: pizza!
Tal vez deba escribir este captulo despus del almuerzo. Lo que obtiene son expresiones lambda
con tipos inferidos. No es un nombre muy romntico, pero es una estupenda herramienta nueva.
Digamos que quera escribir una expresin lambda que multiplica dos nmeros.
Dim mult As Func(Of Integer, Integer, Integer) = _
Function(x As Integer, y As Integer) x * y
sta es la versin con extra queso del cdigo: le digo todo a Visual Basic, y me obedece sin aspa-
vientos. Pero hay una versin menos estricta del cdigo que trae al juego a la inferencia de tipos.
Dim mult = Function(x As Integer, y As Integer) x * y
Figura 9-1. Visual Basic tambin es bueno para jugar a las 20 preguntas.
En este cdigo se supone que tiene Option Infer en On en su cdigo fuente, o que la ha habi-
litado mediante las propiedades del proyecto (es la opcin predeterminada). En el captulo 6 se
analiza esta opcin.
Podramos acortar an ms la definicin mult.
Dim mult = Function(x, y) x * y
En esta lnea, Visual Basic inferira la misma funcin, pero usara el tipo de datos Object en
todo, en lugar de Integer. Adems, si ha establecido Option Strict en On (lo que debera
hacerlo), esta lnea no se compilar hasta que agregue las clusulas As apropiadas.
rboles de expresiones
Internamente, el compilador de Visual Basic cambia una expresin lambda en un rbol de
expresiones, una estructura jerrquica que asocia operandos con sus operadores. Considere esta
expresin lambda semicompleja que eleva una expresin multiplicada a una potencia:
Dim calcularlo = Function(x, y, z) (x * y) ^ z
Visual Basic genera un rbol de expresiones para calcularlo que tiene el aspecto de la figura 9-2.
* z
x y
Cuando llega el momento de usar una expresin lambda, Visual Basic recorre el rbol, calculan-
do valores desde los niveles inferiores a los superiores. Estos rboles de expresiones estn alma-
cenados como objetos basados en clases del espacio de nombres System.Linq.Expressions.
Si no le gusta escribir expresiones lambda puede construir sus propios rboles de expresiones
Lambdas complejos
Aunque las expresiones lambda no pueden contener instrucciones de Visual Basic, como bucles
For...Next, an puede integrar algunos clculos muy complejos empleando operadores estn-
dar. Las llamadas a otras funciones tambin pueden aparecer en lambdas. En este ejemplo de
cdigo, mult difiere su trabajo a la funcin Multiplicarlo:
Private Sub MultiplicarAlgo()
Dim mult = Function(x As Integer, y As Integer) _
Multiplicarlo(x, y) + 10
Eso es muy sencillo. Pero las cosas se ponen ms interesentes cuando tiene expresiones lambda
que devuelven otras expresiones lambda. El clculo lambda fue inventado parcialmente para
ver cmo podra dividirse cualquier funcin compleja en las funciones ms bsicas. Aunque
los valores literales pueden definirse como lambdas. He aqu la expresin lambda que siempre
devuelve el valor 3:
Dim tres = Function() 3
En el clculo lambda, esto puede dividirse en funciones ms pequeas, donde cada una incluye
slo un argumento:
Dim mult2 = Function(x As Integer) Function(y As Integer) x * y
Levantamiento de variables
Aunque puede pasar argumentos en una expresin lambda, tambin puede usar otras variables
que estn dentro del alcance de la expresin.
Private Sub NombrarMiHijo()
Dim logicaNombre = ObtenerLogicaNomenclaturaHijos(
)
MsgBox(logicaNombre("John")) Despliega: Johnson
End Sub
El cdigo real generado por Visual Basic es ms complejo que esto, e incluira todo el cdigo
convertido de delegado de funcin sobre el que se escribi antes. Pero sta es la idea bsica. Las
clases de cierre y el levantamiento de variables son caractersticas esenciales para expresiones
lambda, porque nunca sabe realmente donde estn sus expresiones lambda a todas horas de la
noche.
Inicializadores de objetos
Para inicializar propiedades de objetos no administradas por constructores, necesita asignar estas
propiedades por separado justo despus de que crea la instancia de clase.
Dim nuevaContratacion As New Empleado
nuevaContratacion.Nombre = "Fulano De Tal"
nuevaContratacion.FechaContratado = #2/27/2008#
nuevaContratacion.Sueldo = 50000@
Una nueva sintaxis incluida en Visual Basic 2008 permite combinar la declaracin (con la pa-
labra clave New) y la asignacin de miembro. La sintaxis incluye una nueva variacin de la ins-
truccin With.
Dim nuevaContratacion As New Empleado With { _
.Nombre = "Fulano De Tal", _
.FechaContratado = #2/27/2008#, _
.Sueldo = 50000@}
Bueno, en cuanto a nuevas caractersticas, no es tan brillante como las expresiones lambda o el
levantamiento de variables. Pero hace el trabajo.
Visual Studio 2008 incluye caractersticas que le ayudan a localizar y resolver errores en
tiempo de compilacin. Estos errores estn marcados con una lnea de subrayado azul de-
bajo de la sintaxis ofensora. Algunos errores tambin piden que Visual Studio despliegue
opciones mediante ventanas emergentes, como se muestra en la figura 9-3.
Este cdigo se ve muy razonable, y en casi todos los casos, lo es. Le pide al usuario un n-
mero, convierte nmeros vlidos a formato de enteros y devuelve el resultado. La funcin
EsNumerico eliminar cualquier entrada no numrica que no sea vlida. Al llamar a esta
funcin se devolver cualquier entero vlido entre los valores numricos ingresados, y 0 para
entradas no vlidas.
Pero qu pasa cuando un dictador fascista trata de usar este cdigo? Como lo muestra la
historia, un dictador fascista ingresar un valor como 342304923940234. Debido a que
es un nmero vlido, pasara la pruba EsNumerico con colores vivos, pero como excede el
tamao del tipo de datos Integer, generar el error en tiempo de ejecucin atemorizante
que se muestra en la figura 9-4.
Figura 9-4. Un mensaje de error que slo un dictador fascista puede adorar.
Sin cdigo adicional de manejo de errores o revisiones de lmites vlidos, la rutina Obte-
nerNumero genera este error en tiempo de ejecucin, y luego causa que todo el programa
aborte. Entre cometer crmenes de guerra e ingresar valores numricos no vlidos, parece no
haber fin para el mal que los dictadores fascistas harn.
Errores de lgica
Los errores de lgica son el tercero y ms insidioso tipo de error. Son causados por usted, el
programador; no puede culpar al usuario de esto. Desde los problemas de flujo de procesos
hasta los clculos incorrectos, los errores de lgica son la maldicin del desarrollo de soft-
ware, y llevan a la necesidad de ms tiempo de depuracin que los otros dos tipos de errores
combinados.
Los errores de lgica son demasiado personales y variados para atenderse directamente en
este libro. Puede forzar muchos errores de lgica de su cdigo al agregar revisiones suficien-
tes en busca de datos no vlidos, y al probar adecuadamente su aplicacin bajo diferentes
condiciones y circunstancias.
No tendr muchas dificultades al tratar con errores en tiempo de compilacin. Una com-
prensin general de los conceptos de programacin de Visual Basic y .NET, y el uso regular
de las herramientas incluidas con Visual Studio 2008, ayudar rpidamente a localizarlas y
eliminarlas.
ManejadorDeErrores:
MsgBox("Ha ocurrido un error en 'HacerAlgo':" & _
Err.Description)
Resume Next
End Sub
Cuando ocurre un error, este manejador devuelve de inmediato el control a la lnea que sigue a
la que gener el error. Visual Basic incluye a mtodo abreviado para esta accin.
On Error Resume Next
Al usar la instruccin On Error Resume Next, todos los errores poblarn el objeto Err (al igual
que con todos los errores, no importa cmo se manejen), y luego se omitir la lnea que gener
el error. El usuario no ser informado del error, y continuar usando la aplicacin en un estupor
que indica que la ignorancia es la dicha.
La clusula Try
Las instrucciones Try estn diseadas para monitorear fragmentos de cdigo ms pequeos. Aun-
que podra poner todo el cdigo fuente para su procedimiento dentro del bloque Try, es ms
comn poner dentro de esa seccin slo las instrucciones que es probable que generen errores.
Try
My.Computer.FileSystem.CambiarNombreArchivo(archivoExistente, nuevoNombre)
Catch...
Las instrucciones seguras pueden permanecer fuera de la parte Try de la instruccin Try...
End Try. Se debate mucho sobre lo que constituye exactamente una instruccin de progra-
macin segura, pero dos tipos de instrucciones suelen ser inseguras: 1) las instrucciones que
interactan con sistemas externos, como archivos de disco, recursos de red o hardware, o incluso
bloques de memoria ms grandes, y 2) las instrucciones que pueden causar que una variable o
expresin exceda los lmites diseados para el tipo de datos de esa variable o expresin.
La clusula Catch
La clusula Catch define un manejador de errores. Al igual que con el manejo de errores no
estructurado, puede incluir un manejador de errores global en una instruccin Try, o puede
incluir varios manejadores para diferentes tipos de errores. Cada manejador incluye su propia
palabra clave Catch.
Catch ex As ClaseDeError
El identificador ex proporciona un nombre de variable para el objeto de error activo que puede
usar dentro de la seccin Catch. Puede darle cualquier nombre que desee; y puede variar entre
clusulas Catch, pero no es necesario.
ErrorClass identifica una clase de excepcin, una clase especial diseada especficamente para
proporcionar informacin de error. La clase de excepcin ms genrica es System.Exception;
otra clase de excepcin ms especfica deriva de System.Exception. Como Try...End Try
implementa procesamiento de errores orientado a objetos, todos los errores deben almacenarse
como objetos. .NET Framework incluye muchas clases de excepcin predefinidas ya derivadas
de System.Exception que puede usar en su aplicacin. Por ejemplo, System.DivideByZe-
roException captura cualquier error que surja (obviamente) de dividir un nmero entre cero.
Cuando ocurre un error, su cdigo prueba la excepcin contra cada clusula Catch hasta que
encuentra una clase coincidente. Las clusulas Catch se examinan de arriba abajo, para ase-
gurarse de que pone al final la ms general; si coloca primero System.Exception, ninguna
otra clusula Catch en ese bloque Try se disparar porque todas las excepciones coinciden con
System.Exception. Depender de usted la cantidad de clusulas Catch que incluya, o cules
expresiones monitorea. Si deja fuera todas las clusulas Catch, actuarn de alguna manera como
una instruccin On Error Resume Next, aunque si ocurre un error, se omitirn todas las ins-
trucciones restantes en el bloque Try. La ejecucin contina en el bloque Finally, y luego en
el cdigo que sigue a toda la instruccin Try.
La clusula Finally
La clusula Finally representa la parte haz esto o muere de su bloque Try. Si ocurre un
error en su instruccin Try, el cdigo de la seccin Finally siempre se procesar despus
de que se completa la clusula Catch relevante. Si no ocurre un error, el bloque Finally
an se procesar antes de dejar la instruccin Try. Si usa una instruccin Return en algn
lugar de su instruccin Try, el bloque Finally an se procesar antes de dejar la rutina.
(Esto se est volviendo montono.) Si usa la instruccin Exit Try para salir del bloque Try
antes, an se ejecutar el bloque Finally. Si, mientras se est procesando su bloque Try, su
jefe anuncia que hay una degustacin de comida gratuita en la gran sala de juntas y todos
son bienvenidos, el cdigo Finally tambin se procesar, pero tal vez no est all para
verlo.
Las clusulas Finally son opcionales, de modo que slo debe incluir una cuando la necesite. La
nica ocasin en que las clusulas Finally son obligatorias es cuando omite todas las clusulas
Catch en una instruccin Try.
Errores no manejados
Le mostr antes en el captulo la manera en que los errores no manejados pueden llevar a corrup-
cin de datos, aplicaciones que dejan de funcionar y gastos del congreso fuera de control y en
espiral. Todos los buenos programadores comprenden lo importante que es el cdigo de manejo
de errores, y hacen el esfuerzo adicional de incluir cdigo de manejo de errores estructurado o
no estructurado.
ManejadorDeErrores:
MsgBox("Error manejado.")
Resume Next
End Sub
Cuando ocurre el error en Nivel3, la aplicacin busca un manejador de errores activo en ese
procedimiento, pero no encuentra nada. De inmediato sale de Nivel3 y regresa a Nivel2,
donde busca de nuevo un manejador de errores activo. Ese tipo de bsqueda ser, por tristeza,
infructfera. Con el corazn roto, el cdigo deja Nivel2 y regresa a Nivel1, continuando su
bsqueda de un manejador de errores razonable. Esta vez encuentra uno. El procesamiento salta
de inmediato al bloque ManejadorDeErrores y ejecuta el cdigo de esa seccin.
Si Nivel1 no tuviera un manejador de errores, y ningn cdigo fuera de la pila incluyera uno,
el usuario vera la Ventana de Manejo de Errores de la Miseria (revise la figura 9-4), seguido
por el Programa Muerto de la Desilusin.
Por fortuna, Visual Basic da soporte a un manejador de errores atrapa todo que captura esas
excepciones no manejadas y le permite hacer algo con ellas. Esta caracterstica slo funciona si
tiene el campo Habilitar marco de trabajo de la aplicacin seleccionado en la ficha Aplicacin,
de las propiedades del proyecto. Para acceder a la plantilla de cdigo del manejador de errores
global, haga clic en el botn Ver eventos de aplicacin, en la ficha de propiedades del mismo
proyecto. Seleccione (MiAplicacin eventos) de la lista desplegable Nombre de clase, arriba
de la ventana del cdigo fuente, y luego seleccione UnhandledException de la lista Nombre del
mtodo. El siguiente procedimiento aparece en la ventana de cdigo:
End Sub
Agregue su cdigo de manejo de errores global a esta rutina. El argumento de evento e incluye
un miembro Exception que proporciona acceso a los detalles del error mediante un objeto
System.Exception. El miembro e.ExitApplication es una propiedad Boolean que puede
modificar para continuar o salir de la aplicacin. Como opcin predeterminada se establece en
True, de modo que puede modificarlo si quiere mantener el programa en ejecucin.
Aunque el programa siga ejecutndose, perder la ruta del evento activo que dispar el error. Si ste
surge de un clic en algn botn por parte del usuario, todo el evento Click, y todos sus mtodos
llamados, se abandonarn de inmediato, y el programa esperar una nueva entrada del usuario.
Administracin de errores
Adems de simplemente mirarlos y gritar Error! debe saber algunas otras cosas relacionadas
con la administracin de errores en programas de Visual Basic.
Generacin de errores
Aunque usted no lo crea, habr ocasiones en que tal vez quiera generar errores en tiempo de ejecu-
cin en su cdigo. En realidad, muchos de los errores en tiempo de ejecucin que encontrar en su
cdigo ocurrirn porque Microsoft escribi cdigo en las bibliotecas de clase del marco conceptual
(FCL, Framework Class Libraries) que genera errores de manera especfica. Esto es por diseo.
Digamos que tena una propiedad de clase que era para aceptar slo valores de porcentaje de 0 a
100, pero como tipo de datos Integer.
Private PorcentajeAlmacenado As Integer
Public Property PorcentajeAplicado() As Integer
Get
Return PorcentajeAlmacenado
End Get
Set(ByVal valor As Integer)
PorcentajeAlmacenado = valor
End Set
End Property
Nada es gramaticalmente incorrecto en este cdigo, pero no impedir que alguien establezca el
valor de porcentaje almacenado en 847 o 847, ambos fuera del rango deseado. Puede agregar
una instruccin If al accessor Set para rechazar datos no vlidos, pero las propiedades no pro-
porcionan una manera de regresar un cdigo de estado fallido. La nica manera de informar al
cdigo que llama de un problema consiste en generar una excepcin.
Estoy a punto de usar una palabra que prohib usar a mi hijo que va a la
primaria. Si tiene odos sensibles, cbraselos ahora, aunque no lo proteger
de ver la palabra en la pgina impresa.
Rechazar la instruccin On Error de esta manera es simplemente estpido. Como podra recor-
darlo de captulos anteriores, en su aplicacin .NET todo est orientado a objetos, porque todo
el cdigo aparece en el contexto de un objeto. Si est usando manejo de errores no estructurado,
an puede obtener el objeto de excepcin relevante mediante el mtodo Err.GetException(),
de modo que no es en realidad un problema relacionado con objetos.
Evidentemente, no me preocupa si ocurre un error en las rutinas o no. Si un error causa la salida
temprana de ActualizarParte1, an se llamar a la siguiente rutina, ActualizarParte2,
etc. A menudo necesito un cdigo ms diligente para comprobacin de errores, pero en cdigo
de bajo impacto, esto es suficiente. Sera un poco ms complejo realizar lo mismo empleando
manejo de errores estructurado.
Try
ActualizarParte1()
Catch
End Try
Try
ActualizarParte2()
Catch
End Try
Try
ActualizarParte3()
Catch
End Try
Es una gran cantidad de cdigo extra para la misma funcionalidad. Si odia la instruccin On
Error, use por todos los medios el segundo bloque de cdigo. Pero si es un programador ms
razonable, el tipo de programador que leera un bloque como ste, use cada mtodo adecuado
para su diseo de cdigo.
La clase System.Exception
System.Exception es la clase base de todas las excepciones estructuradas. Cuando ocurre un
error puede examinar sus miembros para determinar la naturaleza exacta del error. Tambin
puede usar esta clase (o una de sus clases derivadas) para construir su propia excepcin persona-
lizada antes de usar la instruccin Throw. En la tabla 9-1 se presenta una lista de los miembros
de este objeto.
Clases derivadas de System.Exception pueden incluir propiedades adicionales que proporcio-
nan detalle adicional de un tipo de error especfico.
El objeto Err
El objeto Err proporciona acceso al error ms reciente mediante sus diversos miembros. En
cualquier momento en que ocurre un error, Visual Basic documenta los detalles del error en
los miembros de este objeto. A menudo se accede a l dentro de un manejador de errores no
estructurado para hacer referencia a los detalles del error, o para desplegarlos. En la tabla 9-2 se
presenta una lista de los miembros de este objeto.
La versin .NET de Visual Basic mejora el objeto Debug con ms caractersticas y un ligero cam-
bio de sintaxis. El mtodo Print se reemplaza con WriteLnea; un mtodo Write separado da
salida a texto sin un retorno de carro final.
Debug.WriteLnea("Reached point G en code")
Todo a lo que d salida usando el mtodo WriteLnea (o similar) va a una serie de escuchas ad-
juntos al objeto Debug. Puede agregar sus propios escuchas, incluida salida a un archivo de trabajo.
Pero en realidad el objeto Debug slo se usa cuando se depura su programa. Una vez que compila
una versin final, ninguna de las caractersticas relacionadas con Debug funciona, por diseo.
Si desea registrar los datos de estado de una aplicacin liberada, considere, en cambio, el uso
del objeto My.Application.Log (o My.Log en programas de ASP.NET). De manera similar
al objeto Debug, Log enva su salida a cualquier nmero de escuchas registrados. Como opcin
predeterminada, toda la salida va a la salida de depuracin estndar (como en el objeto Debug)
y a un archivo de registro creado especficamente para el ensamblado de su aplicacin. Consulte
la ayuda en lnea del objeto My.Application.Log para conocer informacin acerca de la con-
figuracin de este objeto para satisfacer sus necesidades.
Resumen
El mejor programa del mundo nunca generara errores, supongo. Pero vamos, eso no pasa en la
realidad. Si una sonda enviada a Marte y que cost millones de dlares se estrell en un planeta
a millones de kilmetros de distancia, aun despus de aos de ingeniera avanzada, mi aplicacin
para el seguimiento de clientes en una tienda de renta de videos local va a tener uno o dos errores.
Resumen | 273
Proyecto
El cdigo del proyecto de este captulo ser un poco breve. El cdigo de manejo de errores
aparecer en toda la aplicacin, pero lo agregaremos poco a poco a medida que avanzamos en el
proyecto. Por ahora, slo nos concentraremos en las rutinas de manejo de errores que tomarn
alguna accin bsica cuando ocurra un error en cualquier lugar del programa. En cuanto a las
expresiones lambda retendremos ese tipo de cdigo hasta un captulo posterior.
ACCESO AL PROYECTO
Cargue el proyecto Cap09 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap09 (Final) cdigo.
En el proyecto, abra el archivo de clase General.vb, y agregue el cdigo siguiente como un nuevo
mtodo a Module General.
No hay mucho en ese cdigo, verdad? De modo que he aqu cmo funciona. Cuando encuentra un
error en alguna rutina, el manejador de errores aplicado llama al mtodo central ErrorGeneral.
Public Sub AlgunaRutina()
On Error GoTo ManejadorDeErrores
ManejadorDeErrores:
ErrorGeneral("AlgunaRutina", Err.GetException(
))
Resume Next
End Sub
El objetivo del mtodo global ErrorGeneral es simple: comunicar al usuario que ha ocurrido
un error, y seguir adelante. Tiene el objetivo de ser simple, y es simple. Podra mejorar la rutina
con algunas caractersticas adicionales. Registrar el error en un archivo (o cualquier otro escu-
cha de registros activos) podra ayudarle despus sin necesita examinar errores generados por la
aplicacin. Agregue el siguiente cdigo a la rutina, justo despus del comando MsgBox, para
registrar la excepcin.
My.Application.Log.WriteException(elError)
Por supuesto, si ocurre un error mientras est escribiendo en el registro, eso sera un gran proble-
ma, de modo que agregue una lnea ms al principio de la rutina ErrorGeneral.
Proyecto | 275
Como ya hemos hecho que la rutina ErrorGeneral registre nuestros errores, podramos apro-
vecharlo aqu.
Esto es todo para programacin funcional y libre de errores. En el siguiente captulo, en que se
cubren las interacciones con la base de datos, haremos uso frecuente de este cdigo de manejo
de errores.
Si alguna vez ha ledo cualquier libro de programacin relacionado con las tecnologas de desa-
rrollo de Microsoft, ya ley un captulo como ste. Parece que todos los libros de programacin
de Windows tienen un captulo obligatorio sobre interaccin con base de datos. La razn para
esta cobertura extendida no es una sorpresa: Microsoft saca una nueva tecnologa de base de
datos cada dos aos, ms o menos.
Si es nuevo en el desarrollo con Windows, an no ha conocido un compendio de las siguientes
herramientas de interaccin con bases de datos, a veces conflictivas, a veces complementarias:
ODBC: conectividad abierta de base de datos (Open Database Connectivity)
ISAM: mtodo de acceso secuencial indexado (Indexed Sequential Access Method)
DAO: objetos de acceso a datos (Data Access Objects)
RDO: objetos de datos remotos (Remote Data Objects)
OLE DB: vinculacin e incrustacin de objetos para base de datos (Object Linking y Em-
bedding for Databases)
ADO: objetos de datos de ActiveX (ActiveX Data Objects)
Cuando revisa esta lista, podra pensar: Guau, es estupendo. Hay tantas opciones para elegir.
Podra verse engaado al pensar esto. La lista no es estupenda; es terrible. Imagine, slo por un mo-
mento, que no estamos hablando de interfaces de base de datos, sino de otros temas, ms prcticos.
Qu pasa si fuera necesario reemplazar el motor de su carro cada dos aos? Qu pasa si la columna
de direccin tuviera que reemplazarse anualmente? Qu pasa si tuviera que cambiar el aceite cada
5000 kilmetros o tres meses, lo que pase primero? Podra imaginarse la vida en ese mundo?
Cada vez que Microsoft introduca una nueva tecnologa de objetos de base de datos en la mez-
cla, fue seguido rpidamente por una estampida de reprogramaciones para llevar las antiguas
aplicaciones heredadas de Visual Basic (y otras) a la ms reciente tecnologa de base de datos.
Esto no siempre era posible, porque las restricciones de tiempo y presupuesto mantenan a or-
ganizaciones en plataformas antiguas. Durante casi una dcada mantuve una aplicacin en la
lnea del cuarto de milln usando DAO; slo recientemente la actualice a tecnologas de .NET.
277
Qu es ADO.NET?
ADO.NET es un conjunto de clases, incluido con .NET Framework, que representa el mtodo
primario mediante el cual las aplicaciones .NET interactan con bases de datos relacionales y
otros sistemas de administracin de bases de datos abiertos y de propietario. Pero no es slo para
interaccin; en realidad, ADO.NET es, en s, una base de datos relacional que se encuentra par-
cialmente en memoria. Puede crear tablas y relaciones (combinaciones) con objetos de ADO.
NET, agregar y eliminar registros, consultar tablas con base en criterios de seleccin y hacer
tareas simples que son tpicas de sistemas de bases de datos relacionales independientes.
Todas las clases incluidas con ADO.NET aparecen en el espacio de nombres System.Data;
otros espacios de nombres subordinados proporcionan clases derivadas, orientadas a plataformas
especficas de bases de datos. Por ejemplo, el espacio de nombres System.Data.SqlClient
tiene como objetivo bases de datos de SQL Server, y System.Data.OracleClient se con-
centra en sistemas RDBMS de Oracle. Otros proveedores de bases de datos pueden desarrollar
implementaciones afinadas de las diversas clases de ADO.NET para que se usen con sus propios
sistemas, y proporcionarlas como un espacio de nombres separado.
ADO.NET implementa una experiencia de datos desconectada. En la programacin de base de
datos tradicional, sobre todo en aplicaciones de escritorio, la conexin entre una aplicacin y su
base de datos era fija y a largo plazo. Cuando el programa empezaba, la conexin tambin lo ha-
ca. Cuando se sala del programa, varias horas despus, la conexin finalmente terminaba. Pero
en un mundo de sitios Web escalables de manera masiva, mantener una base de datos conectada
por horas, hasta el final, es a veces un desperdicio y, a menudo, resulta imposible.
ADO.NET lo estimula a abrir conexiones de datos slo por el tiempo suficiente para obtener los
datos que satisfacen sus necesidades inmediatas. Una vez que los tiene, cierra la conexin, hasta
la prxima vez que necesite recuperar, insertar o actualizar el contenido de la base de datos. Si
usa la siguiente instruccin:
SELECT * FROM Cliente WHERE SaldoVencido > 0
tiene la opcin de 1) recorrer todos los registros una vez, de una manera rpida y simple; o 2)
cargar los datos en un objeto en memoria parecido a una tabla, cerrar la conexin y trabajar con
Proveedores
Sistemas grandes de base de datos, como SQL Server y Oracle, son servidores independien-
tes (de all el nombre SQL Server, servidor de SQL) que slo interactan indirectamente con
herramientas y aplicaciones de cliente. Estos sistemas, por lo general, aceptan conexiones de red de
clientes a travs de un puerto TCP/IP o una conexin similar. Una vez autentificado, el cliente hace
todas sus solicitudes a travs de esta conexin antes de desconectarse del sistema.
A principios de la dcada de 1990, Microsoft implement ODBC (con base en otros estndares
existentes), como un sistema comn mediante el cual los clientes se conectaran a servidores de
bases de datos, adems de otras fuentes de datos ms simples. Los clientes ya no tenan que pre-
ocuparse por los protocolos de red necesarios para hablar con una base de datos; todo ese cdigo
se inclua en el controlador ODBC.
Ms adelante, Microsoft liber un sistema de conexin a datos llamado OLE DB, basado en la
tecnologa ActiveX. Pronto aparecieron los controladores OLE DB para sistemas comunes, aun-
que an podra obtener recursos de ODBC mediante un controlador genrico ODBC integrado
en OLE DB.
Conjuntos de datos
Si va a hacer ms que slo revisar rpidamente los datos que regresan de una consulta de Data-
Reader, tal vez use un conjunto de datos para almacenar, administrar y, opcionalmente, actuali-
zar esos datos. Cada conjunto proporciona una vista de datos desconectada genrica, sean datos
de un proveedor o datos que gener mediante cdigo. Aunque cada proveedor est unido a una
plataforma de base de datos especfica (como Oracle) o un estndar de comunicacin (como
OLE DB), los objetos en el reino del conjunto de datos son genricos, y pueden interactuar con
cualquier de los proveedores especficos de la plataforma.
Tres objetos principales integran el mundo de los conjuntos de datos:
El objeto DataSet
Cada objeto DataSet acta como una minibase de datos. Puede agregar todas las tablas que
desee a un DataSet, y establecer relaciones de clave externa entre los campos de estas tablas.
Los detalles internos de cada DataSet son un misterio insondable, pero puede exportar un
DataSet completo a XML, y cargarlo de nuevo, ms adelante, si es necesario.
El objeto DataTable
Cada tabla de su DataSet usa un objeto DataTable separado, accesible mediante la co-
leccin Tables del DataSet. Los objetos DataTables tambin son tiles como objetos
independientes. Si planea agregar slo una tabla a su DataSet podra optar por usar slo
un objeto DataTable sin un DataSet. Dentro de cada objeto DataTable, objetos Data-
Column y DataRow separados establecen las definiciones de campo y los valores reales de
datos, respectivamente.
El objeto DataRelation
Use los objetos DataRelation, almacenados dentro de una coleccin Relations de Da-
taSet, para establecer relaciones en el nivel del campo y restricciones entre columnas de sus
objetos DataTable.
Visual Basic 2008 incluye conjuntos de datos con tipos fuertes, una carac-
terstica usada para integrar un DataSet con un formato especfico de los
datos o registros. Pueden resultarle tiles en sus aplicaciones, pero no los ana-
lizar en este libro. La nueva tecnologa LINQ usa una caracterstica similar
para ayudarle a establecer relaciones entre LINQ y tablas de base de datos.
DB
Connection
Command
DataReader
DataAdapter
DataSet
DataTable
DataRow
DataColumn
DataReader
DataTable
Soporte a MARS
Mencion algo llamado MARS en la tabla 10-1. MARS son las iniciales de Multiple Active Re-
sult Sets (conjuntos de resultados mltiples activos). Por lo general, un solo objeto Connection
permite un solo DataReader en uso en cualquier momento determinado. Esta limitacin es bi-
direccional. Si est explorando un DataReader va una instruccin SELECT, no puede usar ins-
trucciones INSERT, UPDATE o DELETE en esa misma conexin, hasta que cierre el DataReader.
Con la introduccin de MARS, una sola conexin puede manejar varias actividades de transmi-
sin de datos en cualquier direccin. SQL Server agreg soporte a MARS con su versin 2005;
Oracle es compatible con caractersticas similares a MARS desde la liberacin inicial de .NET.
Las conexiones de MARS parecen una caracterstica que siempre querr habilitar. Pero agregan
elementos adicionales a su aplicacin que pueden hacerla ms lenta. Adems, MARS no siempre
se combina bien con aplicaciones de varios subprocesos.
2. El segundo paso le pregunta: Qu conexin de datos debera utilizar la aplicacin para co-
nectarse a la base de datos?. Tendremos que crear una nueva conexin para la base de datos
Biblioteca que diseamos en el captulo 4. Haga clic en el botn Nueva conexin.
3. Aparece el cuadro de dilogo Elegir origen de datos. Seleccione Microsoft SQL Server de
la lista Origen de datos y luego haga clic en el botn Continuar. Si ha accedido a este
cuadro de dilogo antes y marc el campo Siempre usar esta seleccin, es posible que
este cuadro de dilogo no aparezca.
4. Aparece el cuadro de dilogo Agregar conexin, para recolectar los detalles de la nueva co-
nexin. Si el campo Origen de datos contiene algo diferente de Microsoft SQL Server,
haga clic en el botn Cambiar, para modificar el tipo de conexin empleando el cuadro de
dilogo mencionado en el paso 3.
5. De regreso al formulario Agregar conexin, llene el campo Nombre del servidor con el nombre
de su instancia de SQL Server. Por fortuna, esta lista desplegable ya tiene las instancias en la lista;
si no, tendr que ingresarla. La opcin predeterminada para SQL Server Express es el nombre
de su equipo, con \SQLEXPRESS adjunto. Si el nombre de su equipo es MISISTEMA, el
nombre de la instancia sera MISISTEMA\SQLEXPRESS.
6. Configure sus parmetros de autentificacin en la seccin Inicio de sesin con el servidor.
Yo us autentificacin estndar de Windows, pero depende de la manera en que configur
los datos en el captulo 4.
7. En la seccin Establecer conexin con una base de datos, seleccione o escriba Biblioteca
para el nombre de la base de datos.
8. Haga clic en el botn Probar conexin, para asegurarse de que todo funciona. Cuando haya
terminado, haga clic en el botn Aceptar para crear la nueva conexin.
9. Muy bien, estamos de regreso en el formulario Asistente para la configuracin de orgenes
de datos. La conexin que acabamos de crear debe aparecer en la lista, como se muestra en
la figura 10-3. Haga clic en Siguiente.
10. El siguiente panel le pregunta si este origen de datos debe volverse parte de los parmetros
configurables para este proyecto. Revisaremos las caractersticas de configuracin de Visual
Basic en el captulo 14. Por ahora, slo acepte la opcin predeterminada y haga clic en Si-
guiente.
11. Casi llegamos al final. Slo faltan 27 pasos! Bromeaba. ste es el ltimo paso en la creacin
del origen de datos. El panel final le muestra una lista de las caractersticas de generacin
de datos de la base de datos Biblioteca. Abra la rama Tablas y seleccione Actividad, como se
muestra en la figura 10-4. Luego haga clic en Finalizar.
Revise el panel Orgenes de datos mostrado en la figura 10-5. Incluye el origen de datos Bi-
bliotecaDataSet con su vnculo con la tabla Actividad.
Con slo arrastrar y colocar, Visual Studio agreg todos los controles y vnculos necesarios
para convertir su formulario en un editor de la tabla Actividad con turbo. Haga la prueba
ahora al oprimir la tecla F5. En la ejecucin del programa puede usar el control de acceso de
grabacin tipo videocasetera de Microsoft Access. Tambin es posible modificar los valores
de cada registro, agregar nuevos o eliminar registros existentes (pero, por favor, regrese las
cosas a su estado original cuando haya terminado; necesitaremos todos los registros originales
ms adelante). Hablando de poder! Hablando de simplicidad! Hablando de lneas no em-
pleadas! Quin necesita programadores pagados como nosotros cuando Visual Studio puede
hacer esto por usted?
Combinacin de datos
En realidad, Visual Studio no est haciendo mucho. Est usando una caracterstica llamada
combinacin de datos para vincular los campos del formulario con el origen de datos, la tabla
Actividad de la base de datos Biblioteca. La combinacin de datos es una caracterstica integra-
da en los controles de Windows Forms que le permiten desplegar y editar valores automtica-
mente en un origen de datos asociado, como una base de datos. Todo est ordenado a travs de
las propiedades del control.
Seleccione el control NombreCompletoTextBox agregado al formulario de este proyecto, y luego
examine sus propiedades. Justo arriba est una seccin de propiedades llamada (DataBindings).
Su subpropiedad Text contiene una referencia ActivityBindingSource NombreCompleto,
una referencia al control que no es de interfaz de usuario ActivityBindingSource tambin
agregada por Visual Studio. ActivityBindingSource, a su vez, contiene una referencia al ob-
jeto BibliotecaDataSet, el origen de datos que creamos antes. Ese origen de datos vincula con
SQL Server, con la base de datos Biblioteca y, por ltimo, con la tabla Actividad y su campo
NombreCompleto. Como comerse un pastelillo!
Por supuesto, reemplace el ID de usuario (sa) y la contrasea (xyz) con sus propios valores. Si quie-
re incluir soporte a MARS en su conexin, agregue otro componente delimitado por punto y coma:
MultipleActiveResultSets=true
Establecimiento de la conexin
Use la cadena de conexin para crear un objeto SqlConnection, y luego abra la conexin. Cree
una nueva aplicacin de Windows Forms en Visual Studio. Agregue un control Button a la su-
perficie de Form1. Haga doble clic en el botn para acceder a su manejador de eventos Click.
Luego agregue el siguiente cdigo al manejador:
' ----- Supone:
' Imports System.Data
Dim bibliotecaBD As New SqlClient.SqlConnection( _
"Data Source=MISISTEMA\SQLEXPRESS;" & _
"Initial Catalog=Biblioteca;Integrated Security=true")
bibliotecaBD.Open()
Asegrese de reemplazar MISISTEMA con el nombre de su propio sistema. Todo este bloque
me parece mucho ms fcil que los 10 o 15 pasos que tuvo que seguir antes cuando se estableci
la conexin mediante Visual Studio.
Al poner juntos todos estos bloques de cdigo se despliega el mensaje mostrado en la figura 10-8.
Cuando haya terminado asegrese de cerrar todas las conexiones que abri. Agregue este ltimo
fragmento de cdigo al final de su manejador de eventos Button1_Click:
resultadosSql.Close()
bibliotecaBD.Close()
Modificacin de datos
La aplicacin de cambios a las tablas de la base de datos est codificada como recuperacin de
datos, pero no se necesita SqlDataReader. En lugar de usar el mtodo ExecuteReader use el
mtodo ExecuteNonQuery, que no devuelve resultados.
SQL Server 2005 tiene una caracterstica conveniente que devolver un solo campo de un nuevo
registro creado mediante la instruccin INSERT. Si busca de nuevo en el diseo de base de datos
del Proyecto Biblioteca, ver que los campos ID en muchas de las tablas se generan automtica-
mente. Por lo general, si quiere recuperar de inmediato el campo ID de un nuevo registro, primero
tiene que usar INSERT con el registro, y luego usar una instruccin SELECT separada, devolviendo
el campo ID del nuevo registro.
INSERT INTO CodigoSerie (NombreCompleto)
VALORES ('Libros infantiles')
La clusula OUTPUT INSERTED de SQL Server combina ambas instrucciones en una sola accin.
INSERT INTO CodigoSerie (NombreCompleto)
OUTPUT INSERTED.ID
VALORES ('Libros infantiles')
Cuando la instruccin INSERT est completa, SQL Server devuelve el campo ID como un conjun-
to de resultados, como si hubiera usado una instruccin SELECT separada. El mtodo Execute
Scalar de SqlCommand es una manera simple de recuperar un solo valor de una consulta SQL.
instruccinSql = New SqlClient.SqlCommand( _
"INSERT INTO CodigoSerie (NombreCompleto) " & _
"OUTPUT INSERTED.ID VALORES ('Libros infantiles')", _
bibliotecaBD)
Dim nuevoID As Integer = CInt(instruccinSql.ExecuteScalar( ))
Luego llame al mtodo Execute apropiado en el comando. Cuando todos los comandos estn
completos, use el mtodo Commit de la transaccin para que los cambios sean permanentes.
conjuntoAtomico.Commit()
Resumen
Hay programadores en este mundo que nunca tienen acceso a una base de datos, quienes
nunca se preocupan por conexiones o transacciones o bloqueo de registros o instrucciones
INSERT o integridad referencial. S, hay ese tipo de programadores en el mundo (cinco, tal vez
seis, de acuerdo con el ltimo conteo). Todos los dems programadores deben incluir cdigo
que administra datos externos de algn tipo, sea en una base de datos relacional, un archivo
XML o un archivo de configuracin. ADO.NET es una de las herramientas .NET que faci-
lita la administracin de esos datos. Es muy diferente del viejo sistema ADO, y an no estoy
convencido de que desconectar datos el 100% del tiempo es la manera correcta de hacer las
cosas. Pero cuando considero el poder y la flexibilidad de ADO.NET, no puedo evitar sino
sentir pena por esos seis programadores que nunca usan bases de datos.
Proyecto
Es probable que ms de 50% del cdigo del Proyecto Biblioteca abarcar directamente una base
de datos, o la manipulacin de los datos recuperados a travs de ADO.NET. Crear constante-
mente nuevos objetos Command y DataReader, aunque simple, es muy duro para los dedos.
Debido a que gran parte del cdigo es repetitivo, el cdigo en este proyecto del captulo tratar
de centralizar parte del cdigo bsico, de patrn o machote.
Para agregar una nueva referencia, haga clic en el botn Agregar, que se encuentra justo debajo
de la lista, y seleccione Referencia, si se le pregunta el tipo de referencia que se agregar. En el
formulario Agregar referencia, la ficha .NET debe estar activa. Es muy sorprendente ver cuntos
ensamblados .NET estn ya instalados en su sistema. Pero no se siente slo a ver lo que pasa:
seleccione System.Data y System.Xml de la lista de componentes, y luego haga clic en el botn
Aceptar. La lista de referencias en las propiedades del proyecto deben incluir ahora las bibliotecas
seleccionadas de espacio de nombres.
Ahora podemos hacer referencia directa a las clases del espacio de nombres System.Data. Pero
escribir System.Data antes de cada uso de una clase relacionada con datos ser tedioso. Po-
demos salpicar con instrucciones Imports System.Data todos los archivos del proyecto, pero
Visual Studio proporciona una solucin ms centralizada. Como an tiene abierta la ficha Refe-
rencias, revise abajo, la seccin Espacios de nombres importados. La larga lista de verificacin
indica cules espacios de nombres deben importarse automticamente a travs de su aplicacin.
Estos espacios no requieren instrucciones Imports separadas en su cdigo, pero ste acta como
Proyecto | 295
El procedimiento ConectarBaseDeDatos contiene todo el cdigo necesario para crear este ob-
jeto. Por ahora, inclu en cdigo la cadena de conexin en la rutina. En un captulo posterior,
incluiremos esa informacin de conexin como parte de un sistema de configuracin. Agregue
la siguiente rutina a su mdulo General. Asegrese de cambiar la referencia a MISISTEMA
por cualquier cosa que sea necesario en su propio sistema.
Proyecto | 297
LimpiarPrograma()
ComboBD
Toma el cdigo numrico asociado con un elemento en un control ComboBox y lo de-
vuelve como una cadena. Si no se selecciona un elemento o si el valor es 1, la rutina
devuelve NULL.
FechaBD(String)
Dada una cadena que contiene una fecha formada, devuelve una fecha lista para usarse en
una instruccin SQL.
FechaBD(Date)
Dado un valor de fecha verdadero, devuelve una fecha de cadena lista para usar en una instruccin
SQL.
Proyecto | 299
Try
' ----- Ver si ya existe la entrada.
textoSql = "SELECT COUNT(*) FROM ValorSistema WHERE " & _
"UPPER(NombreValor) = " & TextoBD(UCase(nombreValor))
If (CInt(EjecutarSQLRegresar(textoSql)) > 0) Then
' ----- El valor ya existe.
textoSql = "UPDATE ValorSistema " & _
"SET DatosValor = " & TextoBD(datosValor) & _
" WHERE UPPER(NombreValor) = " & _
TextoBD(UCase(nombreValor))
Else
' ----- Se necesita crear un valor.
textoSql = "INSERT INTO ValorSistema " & _
(NombreValor, DatosValor) VALUES (" & _
TextoBD(nombreValor) & ", " & _
TextoBD(datosValor) & ")"
End If
Proyecto | 301
De vez en cuando, me resulta necesario modificar la estructura de una base de datos, a tal medida
que las versiones anteriores de una aplicacin dejan de funcionar o causaran dolores de cabeza
importantes. Para evitarlo, agregu un parmetro de versin de base de datos, VersionBaseDa-
tos, y uso este bloque de cdigo para probarlo. Si el programa no coincide con la versin de la
base de datos esperada, se rehusar a ejecutarla.
Ahora que tenemos algunas herramientas bsicas de acceso a base de datos, estamos listos para
empezar a agregar algn cdigo de interaccin con datos reales a la aplicacin Biblioteca.
Los secretos son divertidos. Con miles de millones de personas en el planeta, no estamos cortos
de eventos e historias realmente interesantes, pero ninguna de ellas mantendr nuestra atencin si
hay algn secreto por descubrir en algn otro lugar. Por ejemplo, el anterior director asociado del
FBI, W. Mark Felt, confirm que l era el famoso Garganta Profunda del caso Watergate, pero
no antes de 30 aos de especulacin y cuchicheos acerca de esa identidad secreta. Otros secretos
son igual de intrigantes, aunque conozcamos parte de l. Superman es fascinante en parte debido
a su otro yo secreto, Clark Kent. Muchos libros incluyen la palabra Secreto en su ttulo para hacer
que el libro y su tema sean ms interesantes, como en Los secretos de la cocina japonesa.
En esta era de sobrecarga de la informacin y de estndares morales cada vez ms permisivos
en la televisin, los secretos parecen escasear. Pero todos tienen informacin importante que
necesitan mantener protegida de los dems, y que incluye a los usuarios de sus programas. Por
fortuna, los programas de .NET y los datos relacionados pueden asegurarse de acuerdo con sus
necesidades, si usa las caractersticas de seguridad disponibles en .NET Framework.
He aqu un secreto que le dir justo ahora: no s mucho acerca de problemas de seguridad en equipos
de cmputo. A principios de la dcada de 1980, trabaj para un vendedor de computadoras que esta-
ba saliendo con su propia implementacin del System V de Unix. La compaa necesitaba confirmar
que su producto sera lo suficientemente seguro para ventas gubernamentales, y se me encarg la tarea
de construir una bibliografa de recursos de seguridad computacionales, incluido el famoso Libro
naranja, un documento de estndares de seguridad gubernamentales cuyo ttulo no rima con nada.
Aunque no recuerdo muchos de los detalles de seguridad, s recuerdo que se necesitaran los
camiones de basura de varias ciudades para disponer de todos los materiales con que se cuenta
en seguridad computacional. La bibliografa que desarroll tena ms de 40 pginas! Y slo era
la tabla de contenido. Un artculo que recuerdo era muy interesante. Analizaba la manera en
que las contraseas se generaban en los sistemas Unix, al menos cuando AT&T estaba a cargo
de ste. La parte interesante era que todo el algoritmo estaba impreso en un libro disponible
pblicamente. Cualquiera podra examinar el libro y ver cmo se generaban las contraseas. Y si
estaba familiarizado con Unix, saba que cada contrasea cifrada de usuario estaba almacenada
en texto simple en el archivo /etc/passwd. Pero no era muy importante.
303
Criptografa y cifrado
Conocer un secreto es una cosa. Mantenerlo seguro y protegido de los dems es otra. Asegurarse
de que un enemigo no lo modifique mientras estamos pasndolo (quiero decir, confindolo) a
alguien ms es otro tema. Confirmar que un secreto que viene de alguien ms es confiable es
otro tema. Asegurarse de que obtenga el mejor trato en un seguro de automviles es un asunto
completamente diferente.
Conservar secretos
Cuando las personas piensan en el cifrado y la seguridad de los datos, por lo general se concen-
tran en el aspecto de conservar los secretos. La capacidad para cifrar el contenido criptogr-
ficamente, mantenerlo lejos de un adversario y an conservar la posibilidad de que usted o un
asociado lo pueda descifrar en un momento posterior resulta importante. Las tcnicas de cifrado
van desde las simples aberraciones del lenguaje (como el uso del latn) y las cifras de reemplazo
(sustitucin de letras, usado en los criptogramas) hasta los sistemas de codificacin complejos de
calidad tipo enigma.
El cifrado por software es ahora una parte de la experiencia diaria. Cuando hace compras con
tarjeta de crdito de sitios Web, hay muchas posibilidades de que la informacin de su tarjeta sea
cifrada y transferida con una fidelidad de secreto de 128 bits.
Los mtodos de cifrado usa una o ms claves, adems de una combinacin de funciones de hash
y algoritmos de cifrado, para convertir contenido confidencial en una forma a la que no se tiene
acceso fcil sin la clave original o relacionada. Criptografa simtrica es el nombre usado por m-
todos de cifrado que emplean una sola clave secreta.
El cifrado de clave pblica (tambin conocido como criptografa asimtrica) usa un par de claves
para cifrar y descifrar datos. Una de las claves, una clave pblica, puede darse a cualquier que se
preocupe de comunicarse con usted de manera segura. Puede incluso darla a sus enemigos; es p-
blica. La clave privada relacionada se mantiene segura para que usted la use; nunca la debe mostrar
a nadie, ni siquiera a su madre. El contenido cifrado con una de las claves (y un algoritmo de cifra-
do) slo puede descifrarse ms adelante usando la otra clave. Si su amigo cifra alguna informacin
empleando la clave pblica, nadie excepto usted podr descifrarlo, y requerir su clave privada.
Tambin puede cifrar datos con su clave privada, pero cualquiera podra descifrarlos con la clave
pblica. Veremos los usos para esta accin aparentemente insegura un poco ms adelante.
Verificacin de identidad
Digamos que recibe un correo electrnico de su jefe que dice Ordene 50 ejemplares del nuevo
libro de Tim Patrick, y que sea de prisa. Cmo sabe que este mensaje es confiable, o provie-
ne realmente de su jefe? En este caso, el solo contenido debe probar que es confiable. Pero si
realmente quisiera verificar la fuente, y su jefe no estuviera disponible, podra emplear firmas
digitales para confirmar la identidad del remitente.
El mtodo de firmas digitales emplea cifrado de clave pblica para trasmitir una contrasea o
un mensaje con el que est de acuerdo, y pasar el contenido cifrado con un correo electrnico
ms largo. Por ejemplo, su jefe podra cifrar el texto Soy el jefe empleando su clave privada.
Cuando reciba el correo electrnico podra descifrar la firma digital empleando la clave pblica
de su jefe. Si al descifrar se obtiene el mensaje Soy el jefe, sabra que el mensaje lo hizo, en
realidad, su jefe.
Cifrado en .NET
Las caractersticas de cifrado de datos y seguridad incluidas con .NET aparecen en el espacio
de nombres System.Security.Cryptography. La mayor parte de las clases en este espacio de
nombres implementan varios algoritmos de cifrado bien conocidos que han sido aceptados por
organizaciones y gobiernos como estndares de cifrado confiables. Por ejemplo, la clase DES-
CryptoServiceProvider proporciona caractersticas basada en el algoritmo de estndar de
cifrado de datos (DES, Data Encryption Standard), un algoritmo desarrollado originalmente
por IBM a mediados de la dcada de 1970.
Class CryptoMemoryStream
Public Shared Sub Main()
' ----- Cifrar y descifrar algun texto.
Dim clave As New DESCryptoServiceProvider
Dim versionCifrada() As Byte
Dim versionDescifrada As String
Este cdigo combina una clave de cifrado DES con un flujo, una herramienta comn en las
aplicaciones .NET para transferir datos de un estado o ubicacin a otro. (Los flujos son un
mtodo primario usado para leer y escribir archivos.) No es demasiado difcil usar los flujos,
pero el cdigo an parece un poco complejo. Por qu la clase DESCryptoServiceProvider
no simplemente incluye los mtodos Cifrar y Descifrar? sa es mi pregunta, al menos. Estoy
seguro de que tiene algo que ver con mantener la clase genrica para usarlo en muchos entornos
de datos. Aun as, por muy fragmentado que sea este cdigo, seguro que es ms fcil que escribir
yo mismo el cdigo de cifrado. Y es lo bastante general como para cambiar uno de los otros
algoritmos de clave secreta, sin mucho cambio en el cdigo.
Criptografa asimtrica
En la criptografa de clave secreta, puede usar cualquier clave antigua que desee para dar soporte
al proceso de cifrado y descifrado. Siempre y cuando lo mantenga en secreto, el contenido de la
propia clave en realidad no es demasiado importante. Sin embargo, no puede decirse lo mismo
de la criptografa asimtrica (de clave pblica). Debido a que se usan claves separadas para cifrar
y descifrar los datos, deben crearse claves privadas y pblicas especficas de manera especfica
como un par. No puede slo seleccionar claves pblicas y privadas al azar y esperar que funcio-
nen en conjunto.
Los componentes usados para dar soporte a la criptografa asimtrica incluyen generadores
que emiten pares de clave pblica y privada. Una vez generadas, estas claves pueden usarse en su
cdigo para enmascarar datos confidenciales. Y debido al tamao de clave ms grande, es muy
difcil hackear sus datos cifrados.
El cifrado de clave pblica es notoriamente lento; se toma una eternidad ms un da codificar
grandes cantidades de datos usando la clave de origen. sta es una de las razones por las que
los padres fundadores no usaron el cifrado de clave pblica en la declaracin de independencia.
Debido al rendimiento lento del cifrado asimtrico, muchos sistemas de datos seguros usan una
combinacin de cifrado de clave pblica y de clave secreta para proteger datos. La autorizacin
inicial ocurre con los procesos de clave pblica, pero una vez que se abre el canal seguro, los datos
pasados entre los sistemas se cifran usando mtodos de clave secreta ms rpidos.
.NET incluye dos clases de criptografa de clave pblica para su placer de cifrado y descifrado:
El algoritmo de firma digital (DSA, Digital Signature Algorithm), un algoritmo diseado
por el gobierno de Estados Unidos para usarse en firmas digitales, con soporte principal
mediante la clase DSACryptoServiceProvider.
Uso de hash
Aunque los algoritmos de hash no le dan la capacidad de cifrar y descifrar datos a voluntad, son
tiles para dar soporte a sistemas que aseguran y verifican el contenido de los datos. Usaremos algo
de hash en datos en el cdigo del proyecto de este captulo, de modo que mantngase alerta.
Es fcil crear un algoritmo de hash. Se necesitaron las mejores mentes de la National Security
Agency y el Massachusetts Institute of Technology para generar sistemas de cifrado confiables de
clave secreta y clave pblica, pero puede desarrollar un algoritmo de hash en slo unos minutos.
Hace unos aos escrib mi propio algoritmo de hash que us durante aos en aplicaciones de
negocios. Ese hecho, por s solo, debe probar lo simple y bsico que pueden ser. He aqu un
algoritmo de hash que acabo de escribir mientras estaba sentado:
Public Function HashCiertotexto(ByVal textoOriginal As String) As Long
' ----- Crear un valor de hash de ciertos datos.
Dim valorHash As Long = 0&
Dim contador As Long
En el cdigo, slo sumo los valores ASCII de cada carcter en la cadena de texto, y regreso
el resultado. Hago una revisin en el bucle para asegurar de que no excedo el 90% del valor
mximo Long; no quiero desbordar la variable valorHash y generar un error. Aunque Hash-
Ciertotexto genera una representacin de hash de los datos de entrada, tambin tiene algunas
deficiencias:
Es muy fcil adivinar a partir del valor de hash si el contenido entrante era corto o largo. El
contenido ms corto por lo general generar nmeros pequeos, y los valores de salida ms
largos tienden a indicar contenido de entrada ms largo.
No es muy sensible a algunos tipos de cambios de contenido. Por ejemplo, si reorganiza
varios caracteres en el contenido, probablemente no tendr impacto en el valor de hash. El
cambio de un carcter tendr impacto en el valor, pero si cambia un carcter de A a B y otra
letra cercana de T a S, el valor de hash permanecer sin cambio.
La clase SecureString
Es sorprendente que con todas estas herramientas avanzadas, los programadores an gasten mu-
cho de su tiempo construyendo y analizando datos de cadena. Por fortuna, .NET incluye una
gran cantidad de herramientas tiles de manipulacin de cadenas. Por desgracia, no son muy se-
guras. Puede recordar que las cadenas de .NET son inmutables; una vez creadas, nunca cambian.
Con el tiempo, sern destruidas por el proceso de recoleccin de basura. Pero hasta entonces,
se quedan en la memoria, slo esperando a que sean rastrados por algn cdigo diseado por
hackers. Internamente, los datos de cadena se almacenan como texto simple, de modo que si
alguien accede a la memoria, puede copiar el contenido para fines nefastos.
SecureString al rescate! La clase System.Security.SecureString le permite almacenar
cadenas y hacer que regresen, pero internamente el contenido de la cadena queda cifrado. Si
alguien obtiene el contenido interno de una instancia de clase, parecer garabatos.
Resumen
Cuando crea una aplicacin de negocios para alguna organizacin o departamento, tal vez no le
preocupe mucho la seguridad y la integridad de los datos almacenados por las herramientas de
software. Siempre y cuando los datos pasen de la punta de los dedos del usuario a la base de datos
y regresen, todo es como coser y cantar.
Aunque esa concepcin puede funcionar con muchas aplicaciones, hay sistemas y usuarios que
esperan demasiado en seguridad. En ocasiones, necesita confirmar la seguridad y la integridad
de los datos almacenados por la aplicacin, sobre todo si dejarn los confines de su software o
la base de datos asociada. Las caractersticas de seguridad encontradas en el espacio de nombres
System.Security.Cryptography proporcionan una variedad divertida de opciones de ocul-
tamiento y restauracin de datos.
Proyecto
En este captulo veremos la adicin de las siguientes caractersticas enfocadas a la seguridad del
Proyecto Biblioteca:
El formulario de inicio de sesin, que autentifica a los bibliotecarios y otros usuarios ad-
ministrativos.
Formularios del grupo de seguridad y administracin de usuarios.
ACCESO AL PROYECTO
Cargue el proyecto Cap11 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, Cap11 (Despus) cdigo.
Soporte a autentificacin
Como todos los datos de la biblioteca estn almacenados en una base de datos de SQL Server,
usamos seguridad de Windows o SQL Server para restringir el acceso a los propios datos. Pero
una vez que nos conectamos con la base de datos, usaremos un sistema de autentificacin perso-
nalizado para habilitar y deshabilitar caractersticas en la aplicacin. Es all donde pondremos en
uso las caractersticas de criptografa de .NET.
Antes de agregar el cdigo interesante, necesitamos agregar algunas variables globales que so-
porten la seguridad en toda la aplicacin. Todos los elementos globales aparecen en el archivo
General.vb, dentro del mdulo GeneralCode.
Todas las variables recin agregadas almacenan informacin de identidad del administrador acti-
vo. Cuando un cliente es el usuario activo, el programa establece todos estos valores a sus estados
Proyecto | 313
Cada vez que un administrador trata de usar el sistema, y cada vez que cierra la sesin y regresa
el programa en modo cliente, todas las variables globales relacionadas con la seguridad deben
restablecerse. Esto se hace en el mtodo ReprocesarConjuntoSeguridad, agregado al m-
dulo General.
Try
' ----- Cargar los elementos de seguridad para este usuario.
textoSql = "SELECT IDActividad FROM ActividadGrupo " & _
"WHERE IDGrupo = " & IdGrupoInicio
infoBD = CrearLector(textoSql)
Do While (infoBD.Read)
PerfilSeguridad(CInt(infoBD!IDActividad)) = True
Loop
infoBD.Close()
Catch ex As Exception
' ----- Cierto error relacionado con la base de datos.
ErrorGeneral("ReprocesarConjuntoSeguridad", ex)
If (infoBD IsNot Nothing) Then infoBD.Close(
)
Esta rutina usa cdigo construido en el captulo 10 y captulos anteriores. Cuando detecta a
un usuario autorizado (la variable IdUsuarioInicio), crea un objeto SqlDataReader con las
caractersticas de seguridad permitidas para el usuario, y almacena esos parmetros en la matriz
PerfilSeguridad. Una vez que se ha cargado, un elemento de la matriz que es True representa
una caracterstica de aplicacin que el administrador est autorizado a usar. Analizar la tabla
ActividadGrupo un poco ms adelante, en este mismo captulo.
Si ocurre un error de base de datos durante el procesamiento, el cdigo restablece todo al modo
de cliente, haciendo una llamado recursiva a ReprocesarConjuntoSeguridad para limpiar
la matriz PerfilSeguridad. (La recursin ocurre cuando una rutina se llama a s misma de
manera directa o indirecta.)
Cifrado de contraseas
Todo el contenido de este captulo ha estado construyndose para llegar a este momento, la
seccin donde revelo al ganador de la prxima eleccin presidencial. Momento! Aun mejor
que eso, usar uno de los mtodos hash de .NET para cifrar una contrasea proporcionada por
el administrador antes de almacenarla en la base de datos. Una de las tablas de la base de datos
Biblioteca, NombreUsuario, almacena el perfil de seguridad bsico de cada bibliotecario u otro
Proyecto | 315
Imports System.Text
Imports System.Security.Cryptography
' ----- El valor de hash esta listo, pero me gustan las cosas en
' texto simple cuando es posible. Hay que convertirlo a una
' cadena hexadecimal largo.
For contador = 0 To valorHash.Length - 1
resultado &= Hex(valorHash(contador))
Next contador
Los mtodos primarios para interactuar con los proveedores de seguridad en .NET son median-
te una matriz o un flujo de bytes. Opt por usar el mtodo de la matriz de bytes, convirtiendo
los valores de la cadena a travs del mtodo GetBytes del objeto UnicodeEncoding. Una vez
almacenado como una matriz de bytes, paso el ID de inicio de sesin y la contrasea como ar-
gumentos a las caractersticas de la clase HMACSHA1.
Aunque podra almacenar la salida del mtodo ComputeHash directamente en el campo de la
base de datos, decid convertir el resultado en caracteres ASCII legibles para que las cosas se vean
extraas cuando use instrucciones SQL Server contra la tabla NombreUsuario. Mi conversin es
bsica: convertir cada byte en su equivalente hexadecimal imprimible empleando la funcin Hex
de Visual Basic. Luego slo una los resultados. El campo NombreUsuario.Clave slo contiene
20 caracteres de modo que cortar cualquier cosa ms larga.
Slo para asegurarme de que este algoritmo genera una salida razonable, llam a CifrarClave
con unas cuantas entradas diferentes.
MsgBox("Alicia/nada: " & _
CifrarClave("Alicia", "") & vbCrLf & _
"Alicia/password: " & _
CifrarClave("Alicia", "clave") & vbCrLf & _
"Juan/nada: " & _
CifrarClave("Juan", "") & vbCrLf & _
"Juan/password: " & _
CifrarClave("Juan", "clave"))
Proyecto | 317
Figura 11-1. Quin dice que no puede elegir a sus propios parientes?
Proyecto | 319
Hey, son casi 300 lneas de cdigo fuente. Buena escritura. La clase incluye dos miembros priva-
dos. IDActivo contiene el nmero de ID del registro de la base de datos NombreGrupo desple-
gado, o 1 cuando se editan nuevos registros. La marca EmpezarDeNuevo es un poco ms intere-
Casi todas las rutinas del formulario NombreGrupo proporcionan una sobrescritura simple de
los miembros de base de la clase FormularioCodigoBase. El mtodo UsuarioPuedeAgregar,
que simplemente devuelve False en la clase de base, incluye lgica real en la clase heredada.
Usa la matriz PerfilSeguridad que agregamos antes para determinar si el usuario actual tiene
permitido agregar registros de grupo.
Public Overrides Function UsuarioPuedeAgregar(
) As Boolean
' ----- Revisar el acceso de seguridad del usuario: agregar.
Return PerfilSeguridad(SeguridadBiblioteca.AdministrarGrupos)
End Function
Si revisa el cdigo agregado, encontrar sobrescritura para todos los miembros de Formulario-
CodigoBase, excepto para los mtodos UsaBusqueda y BuscarRegistro. La clase derivada
acepta la accin predeterminada para esos dos miembros.
El usuario agrega, edita y elimina registros de nombre de grupo mediante la sobrescritura de
AgregarRegistro, EditarRegistro y EliminarRegistro, respectivamente, cada uno lla-
Proyecto | 321
Despus de almacenar el ID del registro que habr de editarse en el campo privado IDActivo, el
cdigo carga los datos a travs del mtodo PrepararCamposFormulario, y pide al usuario editar
el registro con la llamada a Me.ShowDialog. El formulario se queda hasta que algn cdigo
o control establece la propiedad DialogResult del formulario. Esto se hace con el evento
AccAceptar_Click, y tambin mediante la propiedad DialogResult del botn AccCan-
celar, que Visual Basic asignar automticamente al formulario cuando el usuario haga clic
en el botn AccCancelar.
La rutina AgregarRegistro es como EditarRegistro, pero asigna -1 al miembro IDActivo
para marcar un nuevo registro. La rutina EliminarRegistro es ms compleja, y usa parte del
cdigo de base de datos que escribimos en el ltimo captulo.
Public Overrides Function EliminarRegistro( _
ByVal idRegistro As Integer) As Boolean
' ----- El usuario quiere eliminar el registro.
Dim textoSql As String
On Error GoTo ErrorHandler
' ----- Confirmar con el usuario.
If (MsgBox("?Realmente desea eliminar el " & _
"grupo de seguridad?", MsgBoxStyle.YesNo Or _
MsgBoxStyle.Question, TituloPrograma) <> _
MsgBoxResult.Yes) Then Return False
' ----- Asegurar que este registro no se usa.
textoSql = "SELECT COUNT(*) FROM NombreUsuario " & _
"WHERE IDGrupo = " & idRegistro
If (CInt(EjecutarSQLRegresar(textoSql)) > 0) Then
MsgBox("No puede eliminar este registro porque " & _
"esta en uso.", MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return False
End If
' ----- Eliminar el registro.
EmpezarTransac()
textoSql = "DELETE FROM ActividadGrupo " & _
"WHERE IDGrupo = " & idRegistro
EjecutarSQL(textoSql)
textoSql = "DELETE FROM NombreGrupo WHERE ID = " & idRegistro
EjecutarSQL(textoSql)
Despus de confirmar la eliminacin con el usuario, una rpida revisin determina si el grupo
an se est usando en algn otro lugar de la tabla NombreUsuario. Si todo resulta bien, el regis-
tro se elimina usando una instruccin SQL DELETE. Como necesitamos eliminar datos en dos
tablas, la envuelvo en una transaccin. Si ocurre un error, el manejador de errores al final de la
rutina revertir la transaccin a travs de RevertirTransac.
Cuando el usuario hace cambios al registro, un clic en el botn Aceptar extrae los datos de la base
de datos. El manejador de eventos AccAceptar_Click verifica los datos y luego los guarda.
If (ValidarDatosFormulario() = False) Then Return
If (GuardarDatosFormulario() = False) Then Return
Me.DialogResult = Windows.Forms.DialogResult.OK
El mtodo ValidarDatosFormulario hace algunas revisiones para ver si los datos son vlidos,
como solicitar que el usuario ingrese el nombre del grupo de seguridad, y que sea nico. Si todo se
ve bien, la rutina GuardarDatosFormulario genera instrucciones SQL que guardan los datos.
Private Function GuardarDatosFormulario(
) As Boolean
' ----- El usuario quiere guardar los cambios.
' Regresar True si es correcto.
Proyecto | 323
ErrorHandler:
Me.Cursor = Windows.Forms.Cursors.Default
Asegrese de revisar las otras rutinas del formulario NombreGrupo; estn all para dar soporte y
mejorar la experiencia de usuario.
Administracin de usuarios
Tambin necesitamos una forma de administrar registros en la tabla NombreUsuario. Como
el cdigo para ese formulario generalmente sigue lo que ya hemos visto en el formulario Nom-
breGrupo, no lo abrumar con detalles. Ya he agregado NombreUsuario.vb a su proyecto, pero
para evitar errores en su cdigo mientras est a mitad del desarrollo, lo deshabilit (al menos en
la versin Antes del cdigo). Para habilitarlo, seleccione el archivo en la ventana Explorador
de soluciones, Luego, en el panel Propiedades, cambie la propiedad Accin de compilacin de
Ninguna a Compilacin.
El nico cdigo interesante de este formulario es que maneja la contrasea de manera diferente
del formulario NombreGrupo. Para asegurar las cosas lo ms posible, en realidad no cargo la
contrasea guardada en el campo Clave. No hara ningn bien de todos modos, porque he al-
macenado una versin con hash aplicado en la base de datos.
Como uso el Id de inicio de sesin del usuario como clave secreta cuando cifro la contrasea,
debo volver a generarla, si el usuario cambia alguna vez el ID de inicio de sesin. El campo Id
InicioOrigen privado mantiene una copia del ID de inicio de sesin cuando el formulario se
abre por primera vez, y revisa cualquier cambio cuando vuelve a guardar el registro. Si ocurren
cambios se vuelve a generar la contrasea.
resultadoClave = CifrarClave(Trim(RegistroIdInicio.Text), _
Trim(RegistroClave.Text))
El uso de los formularios de edicin NombreUsuario y NombreGrupo requiere algn cdigo adi-
cional en el formulario principal. Agrguelo donde se indica en el archivo FormularioPrincipal.vb.
Proyecto | 325
Figura 11-2. El formulario oficial de inicio de sesin administrativo del Proyecto Biblioteca.
No fue mucho cdigo. Agregue tambin al formulario el cdigo del mtodo MostrarFormInicio.
Tambin habilitemos la tecla F12 para que acte como desencadenador de inicio de sesin.
Agregue el siguiente cdigo a la instruccin Select Case en el manejador de eventos Formu-
larioPrincipal_KeyDown.
Case Keys.F12
' ----- Preguntar al usuario si va a modo de cliente o administrativo.
MostrarFormInicio()
e.Handled = True
Proyecto | 327
If (PerfilSeguridad(SeguridadBiblioteca.EjecutarInformes)) Then _
PanelInformes.Visible = True
con cdigo que revisa los parmetros de seguridad antes de mostrar el panel.
Proyecto | 329
Alguna vez ha deseado hacer cosas ms all de lo que las personas estn diseadas para hacer?
Cmo volar? Todos soamos con eso, pero no podemos hacerlo sin varios cientos de kilos de
turbosina. O qu tal doblar el acero con nuestras manos? Le suena a alguien que conoce?
Tambin estn las opciones de respirar bajo el agua, hacer divisiones de grandes nmeros en la
mente, hablar un idioma extranjero con soltura sin mucho estudio y tener una carrera exitosa
como autor de libros populares de computacin. Ah, uno puede soar.
No es que queramos hacer todo esto, sino que de vez en cuando sera agradable mejorar ligera-
mente con la habilidad para hacer una o dos cosas que estn ms all de nuestras capacidades.
Por desgracia, no funciona para los seres humanos con mucha frecuencia, pero podra funcionar
para los operadores de .NET?
Tal vez ni siquiera sabe que el humilde operador de suma (+) de Visual Basic tiene sueos de
volar, o de hablar hngaro, o de doblar el acero. Bueno, los operadores tambin son personas.
Y ahora sus sueos pueden satisfacerse porque Visual Basic es compatible con la sobrecarga de
operadores.
En este captulo se le mostrar cmo puede dirigir el proceso de mejora de los diversos opera-
dores de Visual Basic. Tambin presentar los mtodos de extensin, que le permiten mejorar las
clases de manera similar, aunque no tenga acceso al cdigo fuente original para esas clases.
Qu es la sobrecarga de un operador?
La sobrecarga de operadores le permite a su cdigo mejorar los operadores bsicos de Visual
Basic y dotarlos con habilidades que el compilador no les haba otorgado previamente. La
sobrecarga no cambia la sintaxis usada cuando se emplean operadores, pero s cambia los tipos
de objetos que cada operador puede administrar. Por ejemplo, el operador de multiplicacin
(*) por lo general slo interacta con nmeros, pero puede hacer que trabaje con su propia
clase Abejorro.
Dim enjambre As Abejorro
Dim unAbejorro As New Abejorro
330
Los operadores binarios aceptan dos operandos, uno a cada lado del operador. El operador de
multiplicacin es un operador binario:
diez = dos * cinco
La naturaleza de un operador es que una vez que ha hecho su trabajo, el operador y su operando
o sus operandos son reemplazados por el resultado calculado. La expresin 10/5 es reemplaza-
da por el resultado 2 calculado, y este resultado se usa para completar cualquier instruccin o
expresin en que aparece la operacin original. Trabaja como una funcin.
' ----- Estas dos lineas (tal vez) colocan el mismo
' resultado calculado en laRespuesta.
laRespuesta = 2 * 5
laRespuesta = Duplicarlo(5)
Para estar listo para la sobrecarga de operadores, modifique su mente para ver a los operado-
res como funciones. Revise ms all de los confines del universo de su operador, y brase a la
verdad de que los operadores y las funciones son uno mismo. Si alguna vez ha programado en
LISP, realmente lo siento por usted. Pero ya comprende tambin que los operadores son como
funciones. En LISP, todo es una funcin. Para multiplicar dos nmeros en LISP, usa la sintaxis
de prefijo, donde el nombre del operador aparece primero. La expresin siete por tres utiliza
esta sintaxis:
(* 7 3)
Una vez completada, se reemplaza toda la expresin entre parntesis, como en un una funcin,
por su respuesta. La expresin LISP:
(+ 2 (* 7 3))
se vuelve:
(+ 2 21)
El operador (*) se vuelve un nombre de funcin, y los operandos juegan el papel de parmetros
de la funcin, generando al final un valor expuesto a travs del valor devuelto por la funcin.
Aunque los operadores no estn definidos como funciones de esta manera en Visual Basic, la
sobrecarga de estos operadores si lo estn.
Para sobrecargar el operador de multiplicacin en nuestra clase imaginaria Abejorro, usamos
la palabra clave Operator para definir una funcin de multiplicacin para operandos de la
clase Abejorro.
Partial Class Abejorro
Public Shared Operator *(ByVal operando1 As Abejorro, _
ByVal operando2 As Abejorro) As Abejorro
' ----- Multiplicar dos abejorros.
Dim resultadoFinal As New Abejorro
Ahora, cuando multiplica dos instancias de Abejorro con el operador de multiplicacin, Vi-
sual Basic reconoce el patrn operando1 * operando2 como coincidencia con un operador de
multiplicacin sobrecargado con dos argumentos Abejorro, y llama a esta funcin Operator
basada en una clase para obtener el resultado.
Todas las declaraciones Operator deben incluir las palabras claves Public y Shared. Si se com-
partieran, se requerira que Visual Basic creara una instancia adicional de la clase tan slo para
acceder al cdigo de operador sobrecargado, y eso no sera muy eficiente.
Qu puede sobrecargar?
Puede cargar casi todos los operadores estndar de Visual Basic (excepto por Is e IsNot), adems
de algunas otras caractersticas. En esta seccin se describe cada operador que es posible sobrecar-
gar, agrupado por tipo general. Cada seccin incluye una tabla de operadores. Para sobrecargar
un operador en una clase, use el nombre de la columna Operador como nombre de la funcin. Si
hubiera un operador llamado XX, la instruccin Operator coincidente sera:
Public Shared Operator XX(...)
En la tabla 12-1 se presenta una lista de los operadores matemticos compatibles con sobrecarga.
Operadores de comparacin
Visual Basic incluye siete operadores de comparacin bsicos, la mayor parte de ellos usados en
instrucciones If y expresiones similares que requieren un clculo condicional booleano. Los m-
todos Operator para estos operadores de comparacin tienen la misma sintaxis que la usada por
los operadores matemticos, pero casi todos ellos deben implementarse en pares. Por ejemplo,
si sobrecarg el operador de menos que (<), Visual Basic requiere que sobrecarga el operador de
ms que (>)dentro de la misma clase, y para la misma firma de argumentos.
Todos los operadores de comparacin son operadores booleanos. Aunque puede modificar los
tipos de datos de los argumentos pasados al operador, todos deben regresar un valor booleano.
Public Shared Operator <=(ByVal operando1 As AlgunaClase, _
ByVal operando2 As AlgunaClase) As Boolean
' ----- El operador <= devuelve un resultado booleano.
End Operator
En la tabla 12-2 se presentan seis de los siete operadores bsicos de comparacin que puede
sobrecargar. Cada entrada incluye un valor compaero que identifica el operador coincidente
que tambin debe sobrecargarse.
No tiene que usar las mismas reglas de patrones cuando sobrecarga el operador Like, y puede aceptar
cualquier tipo de datos para el operando de patrn, pero an debe devolver un resultado booleano.
Public Shared Operator Like(ByVal operando1 As Abejorro, _
ByVal operando2 As Integer) As Boolean
' ----- Ver si Abejorro coincide con un patron Entero.
End Operator
Tabla 12-3. Los operadores lgicos y en el nivel de bits que pueden sobrecargarse.
Operador Comentarios
<< El operador de desplazamiento a la izquierda realiza un desplazamiento de bits en un valor entero de origen, moviendo
los bits a la izquierda un nmero especfico de posiciones. Aunque no tiene que usar este operador para realizar un verda-
dero desplazamiento de bits, debe aceptar una cantidad de desplazamiento (un Integer) como segundo operando.
Public Shared Operator <<(ByVal operando1 As Abejorro, _
ByVal operando2 As Integer) As Abejorro
' ----- Agregar aqui codigo de desplazamiento.
End Operator
>> El operador de desplazamiento a la izquierda realiza un desplazamiento de bits igual que el de desplazamiento a la
izquierda, pero mueve los bits a la derecha. Supongo que hace a esos bits conservadores. Su cdigo puede hacer
que el valor devuelto sea ms liberal, si lo quiere, pero al igual que con el operador de desplazamiento a la izquierda,
debe aceptar un Integer como segundo operando.
Not El operador de negacin en el nivel de bits es unario, aceptando slo un argumento de operando.
And El operador de unin en el nivel de bits establece un bit en el valor devuelto si tambin estn establecidos ambos bits
con igual posicin en los operandos de origen.
Operador Comentarios
Or El operador de disyuncin en el nivel de bits establece un bit en el valor devuelto si est establecido cualquier de los
bits con igual posicin en los operandos de origen.
Xor El operador de exclusin en el nivel de bits establece un bit en el valor devuelto si slo est establecido uno de los
bits con igual posicin en los operandos de origen.
IsTrue La sobrecarga del operador Or no sobrecarga automticamente el operador OrElse relacionado. Para usar Or
Else, debe sobrecargar el operador especial IsTrue. No se trata de un operador real de Visual Basic, y no puede
llamarlo directamente cuando lo sobrecarga. Pero cuando usa el operador OrElse en lugar de un operador Or
sobrecargado, Visual Basic llama al operador IsTrue cuando es necesario. Debe seguir unas cuantas reglas para
usar el IsTrue sobrecargado:
El operador Or sobrecargado debe devolver el tipo de la clase en que est definido. Si quiere usar OrElse en la
clase Abejorro, la sobrecarga del operador Or en esa clase debe devolver un valor de tipo Abejorro.
El operador IsTrue sobrecargado debe aceptar un solo operando del tipo de la clase contenedora (Abejo-
rro), y devolver un valor booleano.
Debe sobrecargar el operador IsFalse.
La manera en que determina la verdad o falsedad de un Abejorro depende de usted.
IsFalse La sobrecarga de IsFalse funciona como la de IsTrue, y tiene reglas similares, pero se aplica a los operadores
And y AndAlso.
El operador CType
La caracterstica CType de Visual Basic se parece ms a una funcin que a un operador:
resultado = CType(origen, tipo)
Pero las apariencias engaan. No es una verdadera funcin, y como las dems funciones de con-
versin (como CInt), en realidad se procesa en tiempo de compilacin, mucho antes de que el
programa siquiera se ejecute. Al permitirle sobrecargarlo como un operador, Visual Basic le per-
mite crear conversiones personalizadas y especiales entre tipos de datos que no parecen compati-
bles. La siguiente plantilla de mtodo convierte un valor de tipo Abejorro en un Integer:
Public Shared Operator CType(ByVal operando1 As Abejorro) _
As Integer
' ----- Realizar conversion aqui, devolviendo un Integer.
End Operator
Si trata de escribir ese ltimo bloque de cdigo en Visual Basic, se quejar de que le falta la pa-
labra clave Widening o Narrowing (vase la figura 12-1).
Y es obvio por qu fallan: una variable Byte no puede contener un valor 5000. Pero qu pasa
con este cdigo?
Dim muyGrande As Short = 5
Dim muyChico As Byte
' ----- Las dos lineas siguientes son correctas.
muyChico = muyGrande
muyChico = CByte(muyGrande)
Se ejecutarn bien, porque 5 cabe en una variable Byte con espacio suficiente. (Si Option
Strict est establecido en On, la primera asignacin no podr compilarse.) An as, nada me
detendr de reasignar un valor de 5000 a muyGrande y tratar de asignarlo de nuevo. El problema
es la posibilidad de falla durante la conversin.
Cuando una conversin tiene la posibilidad de fallar debido a que los datos de origen no
caben completamente en la variable de destino, se trata de una conversin de estrechamien-
to. Este tipo de conversiones son una realidad, y siempre y cuando haya revisado los datos
antes de la conversin, no hay ninguna razn para restringir de manera permanente estas
conversiones.
Las conversiones de ensanchamiento van en la direccin opuesta. Ocurren cuando cualquier valor
de origen en el tipo de datos original siempre cabr fcilmente en el tipo de destino. Una con-
versin de estrechamiento siempre ser correcta si los datos de origen son vlidos.
Visual Basic permite que las conversiones de ensanchamiento ocurran automtica, implcita-
mente. No tiene que usar explcitamente CType para forzar la conversin. Si tiene una conver-
sin de ensanchamiento de Abejorro a Integer, tiene Option Strict en On, el siguiente
cdigo debe funcionar muy bien:
Dim valorOrigen As New Abejorro
Dim valorDestino As Integer = valorOrigen
La clase es muy simple; existe para mantener una cuenta simple de abejas. Pero al sobrecargar los
operadores de suma, resta, multiplicacin y CType, podemos usar instancias de abejas con una
sintaxis ms natural.
Dim grupoEstudio1 As New Abejorro(20)
Dim grupoEstudio2 As New Abejorro(15)
Dim grupoEnjambre As Abejorro = grupoEstudio1 * grupoEstudio2
MsgBox("El enjambre contiene " & CInt(grupoEnjambre) & " abejas.")
La ejecucin correcta de este cdigo genera un enjambre de 300 abejas y el mensaje de la figura 12-2.
La inclusin de una sobrecarga de CType que genera un Integer me permiti convertir Abe-
jorro usando el operador CInt. Tambin pude haber cambiado la ltima lnea para usar el
verdadero operador CType.
MsgBox("El enjambre contiene " & _
CType(grupoEnjambre, Integer) & " abejas.")
Requisitos de declaracin
Como ya mencion, siempre debe hacer que los mtodos Operator sean Public Shared. Y
debido a que los operadores sobrecargados necesitan una especie de conexin ntima con su
clase contenedora, por lo menos uno de los operandos o el valor de regreso debe coincidir con
el tipo de la clase contenedora. (En algunas sobrecargas, Visual Basic impone que sea uno de los
operandos el que coincide.) Cualquier de las dos sobrecargas siguientes funcionar bien, porque
Abejorro se usa para uno de los operandos:
Public Shared Operator <=(ByVal operando1 As Abejorro, _
ByVal operando2 As Integer) As booleano
' ----- Comparar un Abejorro con un valor.
Sin embargo, no puede establecer ambos operandos en un tipo que no sea Abejorro al mismo
tiempo y an mantener la sobrecarga en la clase Abejorro.
Class Abejorro
Public Shared Operator <=(ByVal operando1 As Date, _
ByVal operando2 As Integer) As booleano
' ----- This will not compile.
End Operator
End Class
Sobrecarga de la sobrecarga
Puede sobrecargar operadores sobrecargados. No, querido editor, no escrib la misma palabra
dos veces por error. Puede agregar mltiples variaciones de la firma de argumentos y valor de
regreso de un operador sobrecargado a una sola clase.
Public Shared Widening Operator CType( _
ByVal operando1 As Abejorro) As Integer
' ----- Realizar aqui conversion a Integer.
End Operator
Siempre y cuando las firmas de argumentos o los valores devueltos difieran puede agregar todas
las sobrecargas de un operador que desee. Tampoco necesita usar la palabra clave Overloads.
Sea amable
Es correcto. Sea amable. No slo porque tenga el poder de redefinir la suma para que sea una
divisin, tiene que ser molesto. No haga que los programadores de mantenimiento que tienen
que modificar su cdigo ms adelante trabajen ms debido a su malvada sobrecarga de operado-
res. Cuando agregue sobrecargas, deje que el significado de la nueva caracterstica por lo menos
tenga la sensacin del operador original. Mis compaeros programadores de mantenimiento y
yo se lo agradeceremos.
Mtodos de extensin
Qu pasa si quiere modificar el comportamiento de una clase, pero no tiene acceso al cdigo
fuente? Podra derivarlo de ella y generar una nueva clase, pero no siempre es conveniente.
el texto que aparece en el cuadro de mensaje estar en maysculas porque el mtodo ToUpper
devuelve una nueva versin en maysculas de la instancia de cadena original. Un mtodo To-
Lower equiparable funciona a la inversa, pero lo que realmente quiero es el mtodo ToTitle
que capitaliza slo la primera palabra de cada palabra.
MsgBox(cadenaImpositiva.ToTitle())
La clase String no incluye un mtodo ToTitle, pero podemos agregarlo gracias a los mtodos
de extensin. Para crear un mtodo de extensin, cree un mtodo dentro de un mdulo estndar
que acepta el tipo de datos de destino como primer parmetro.
Module MyExtensions
<System.Runtime.CompilerServices.Extension(
)> _
Public Function ToTitle(ByVal textoOrigen As String) As String
Return StrConv(textoOrigen, VbStrConv.ProperCase)
End Function
End Module
Por lo general, llamara a esta funcin como est, pasndola en la cadena original.
MsgBox(ToTitle(cadenaImpositiva))
Y ese cdigo s funciona, pero la adicin del atributo Extension (del espacio de nombres Sys-
tem.Runtime.CompilerServices) convierte ToTitle en un mtodo de extensin, extendien-
do los tipos de datos String. Su cdigo en realidad no est modificando String. Tras bamba-
linas, el compilador de Visual Basic est convirtiendo la sintaxis parecida a un mtodo nuevo en
una sintaxis parecida a una funcin antigua en cada uso de ToTitle.
En s mismos, los mtodos de extensin no hacen mucho. Llamar a ToTitle(cadenaImpositiva)
no es tan diferente de cadenaImpositiva.ToTitle(). Pero al igual que con muchas nuevas
caractersticas de Visual Basic 2008, los mtodos de extensin se agregaron slo para elevar el
precio del producto. Estoy bromeando! En realidad, la nueva caracterstica de mtodos de ex-
tensin es un soporte importante para la nueva tecnologa LINQ.
Proyecto
En el proyecto de este captulo se agregar una gran cantidad de cdigo a la aplicacin Bibliote-
ca; casi 25% de todo el cdigo bsico. Gran parte de l es idntico al cdigo que agregamos en
captulos anteriores, de modo que para qu imprimirlo aqu. Hay mucho que leer, tambin, de
modo que no lo sobrecargar con el pegado de fragmentos de cdigo por aqu y por all. Pero
mientras agrega cada nuevo formulario al proyecto, asegrese de revisar su cdigo antes de fami-
liarizarse con su funcionamiento interno.
ACCESO AL PROYECTO
Cargue el proyecto Cap12 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap12 (Final) cdigo.
Ese cdigo es correcto. Pero pienso No sera adecuado convertir la instancia DatosLista
Elementos a un Integer empleando la funcin CInt, y no tener que mezclarse con variables
de miembro como DatosElemento?
Hmm. El cdigo no es tan diferente. Pero hey, por qu no? Hagmoslo. Para dar soporte a esta
conversin, necesitamos agregar la sobrecarga de CType a la clase DatosListaElementos. Abra
el archivo de la clase y agregue el siguiente cdigo como un miembro de la clase.
El programa Biblioteca identifica libros y otros elementos que estn almacenados en varios luga-
res, como diversas sucursales o almacenes. LugarPredeterminadoElemento indica cul de esas
ubicaciones, de la tabla CodigoLugar, es la predeterminada. La entrada LugarPredetermina-
do de la tabla ValorSistema de la base de datos almacena este valor de manera permanente.
Cuando se buscan libros, autores y otras cosas que podran dar como resultado miles de coinci-
dencias, LimiteCoincBusqueda indica el nmero mximo de coincidencias devueltas por estas
bsquedas. Se almacena como el valor del sistema LimiteBusqueda.
Proyecto | 343
ConfirmarLugarPredeterminado
Esta rutina verifica que existe una entrada vlida LugarPredeterminado en la tabla Va-
lorSistema. Devuelve True si es correcta.
ObtenerCopiaDisposicion
Esta rutina proporciona una corta descripcin del estatus actual de una copia del artculo
de la biblioteca especfica. Analiza los registros de artculos y clientes, y devuelve una de las
siguientes cadenas de cdigo de estatus: Nueva Copia Articulo, Regresado, Prestado,
Vencido, Faltante o Referencia.
<System.Runtime.CompilerServices.Extension(
)> _
Public Function FormarNombreAutor( _
ByRef infoBD As SqlClient.SqlDataReader) As String
' ----- Dado un registro de autor, regresar el nombre formado.
Dim nombreAutor As String
Podramos dejar afuera las caractersticas del mtodo de extensin con slo omitir el atributo
Extension. Luego, las llamadas para la formacin de autor tendra este aspecto:
FormarNombreAutor(infoBD)
Proyecto | 345
Figura 12-3. El formulario LimitarArticulos acta como el encargado de sacar a los clientes molestos de un bar, en
este caso en relacin con los elementos de una lista.
El formulario permite al usuario recuperar todos los registros, o elementos especficos basados en
el nombre del elemento (con soporte a comodines). Una vez que se cargan las coincidencias, el
usuario puede acceder de nuevo a este formulario al hacer clic en el botn Buscar del formulario
ListaRegistrosEditados para estos tipos de editores de cdigo que dan soporte a bsquedas
(autores, artculos, clientes y editores).
Estamos listos para incluir estos cuatro formularios de limitacin de bsqueda al proyecto:
LimitarAutor.vb
Este formulario limita los registros de autor, como se cargan de la tabla Autor.
LimitarArticulos.vb
ste es el formulario del que acabamos de hablar. Limita el despliegue de los elementos de
biblioteca de la tabla ArticuloConNombre.
LimitarCliente.vb
Slo en caso de que los clientes estn volando hacia su biblioteca, este formulario le permite
limitar los registros cargados de la tabla Cliente.
LimitarEditor.vb
Este formulario limita los registros de la tabla Editor.
Figura 12-4. Los primeros dos de tres pasos del asistente para autores.
Proyecto | 347
Observa la primera lnea lgica de ese cdigo? Utilizamos la funcin de conversin CInt
para obtener un valor de DatosElemento de un elemento de la lista. Esto llama a nuestro
operador CType sobrecargado en la clase DatosListaElementos.
AgregarLocalizarEditor.vb
Este formulario es como AgregarLocalizarAutor, pero se concentra en los editores. Su
asistente slo tiene dos pasos porque los editores no estn agrupados por tipo. Localiza y agre-
ga registros a la tabla Editor. Cuando es hora de agregar un editor a un artculo, el formulario
del editor del elemento llama a la funcin pblica AgregarLocalizarEditor.Preguntar
Usuario. Esta funcin devuelve el ID del registro del editor seleccionado, o -1 para abortar
la adicin de un editor. Un valor devuelto de -2 limpia cualquier ID de editor seleccionado.
AgregarLocalizarSerie.vb
El formulario es similar a AgregarLocalizarEditor, pero pide registros de la tabla Co-
digoSerie.
EditarAutorArticulo.vb
Una vez ms, se ha agregado un autor a un artculo, la nica manera de cambiarlo a un
autor diferente consiste en eliminar el autor incorrecto y agregar el correcto por separado
mediante el formato AgregarLocalizarAutor. Pero si el usuario simplemente seleccion
el tipo de autor equivocado (como Editor en lugar de Ilustrador), es una carga buscar
de nuevo el nombre del autor para cambiar el tipo. El formulario EditarAutorArticulo
permite que el usuario modifique el tipo de un autor ya agregado a un elemento. Modifica
el campo de la base de datos AutorArticulo.TipoAutor.
Algo interesante que tiene este formulario es soporte para leer cdigos de barras. Muchos lec-
tores de cdigos de barras actan como una cua, insertando el texto de un cdigo de barras
escaneado en un flujo de entrada de teclado de la computadora. Cualquier programa que
monitoree cdigos de barras simplemente tiene que monitorear entrada normal de texto.
Los escneres de cdigo de barras adjuntan un retorno de carro (la tecla Enter) al final del
cdigo de barras transmitido. Esto permite que un programa detecte el final del nmero de
cdigo de barras. Pero en casi todos los datos del programa Biblioteca, la tecla Enter dispara el
botn Aceptar y cierra el formulario. No queremos que esto suceda aqu. Para evitarlo, agre-
garemos algn cdigo a este formulario que deshabilita el clic automtico en el botn Aceptar
cada vez que el punto de insercin est en el campo de entrada de texto CodigoBarras.
Proyecto | 349
Con este cdigo, cuando el usuario oprime la tecla Enter en el campo CodigoBarras ma-
nualmente, el formulario no se cierra. Pero es un pequeo precio que hay que pagar para el
soporte a cdigo de barras.
El usuario puede incluir el asterisco (*) como comodn en las partes de nombre o apelli-
do. El asterisco se ha vuelto un carcter comn para usar en todos los tipos de bsqueda
con comodn. Por desgracia, no es soportado en las instrucciones SELECT de SQL Server,
que usa, en cambio, el carcter de porcentaje (%) como comodn (como muchas otras
plataformas de base de datos que cumplen con SQL). Como BuscarRegistros extrae
el apellido y el nombre, asegrese de que se usa el carcter comodn adecuado.
' ----- Usar los limites para ayudar a preparar el texto de busqueda.
limiteApellido = Trim(ObtenerSubCadena(limiteUsuario, ",", 1))
limiteNombre = Trim(ObtenerSubCadena(limiteUsuario, ",", 2))
If ((limiteApellido & limiteNombre) = "") Then Return
If (InStr(limiteApellido, "*") = 0) Then limiteApellido &= "*"
If (InStr(limiteNombre, "*") = 0) Then limiteNombre &= "*"
limiteApellido = Replace(limiteApellido, "*", "%")
limiteNombre = Replace(limiteNombre, "*", "%")
Por lo general, Imports es seguido de inmediato por un espacio de nombres. Esta variacin in-
cluye el prefijo MVB =, que define un mtodo abreviado para el espacio de nombres Microsoft.
VisualBasic de cdigo en este archivo. Si Visual Basic importa demasiados espacios de nom-
bres en una clase existente que tambin define una gran cantidad de miembros pblicos, est lla-
mado a tener conflictos entre nombres de miembro. En este caso, el conflicto est en el miembro
del formulario Left. Debido a que este cdigo fuente para el formulario Autor ve todo a travs
del prisma de ese formulario, cuando incluye la palabra clave Left en su lgica, el cdigo supone
de manera natural que se refiere a la propiedad Left del formulario, lo que establece la posicin
izquierda del formulario. El problema es que Left tambin es una funcin comn de manipula-
cin de cadena que extrae los caracteres del extremo izquierdo de una cadena ms larga:
cadenaMasCorta = Left(cadenaMasLarga, 5)
En un formulario, este cdigo genera un error, porque piensa que Left se refiere a Me.Left.
Para usar la versin de cadena de Left, tiene que incluir su espacio de nombres como prefijo:
cadenaMasCorta = Microsoft.VisualBasic.Left( _
cadenaMasLarga, 5)
La instruccin especial Imports nos permite usar un sustituto ms corto para el espacio de
nombres ms bien largo Microsoft.VisualBasic:
cadenaMasCorta = MVB.Left(cadenaMasLarga, 5)
Proyecto | 351
Figura 12-6. La parte inferior del formulario Autor que muestra Nombres coincidentes.
Este campo ayuda al usuario a evitar la adicin del mismo autor a la base de datos dos ve-
ces. A medida que se hacen cambios a los campos Apellido y Nombre, el campo Nombres
coincidentes obtiene actualizaciones de nombres de autor encontrados en la tabla Autor.
La rutina ActualizarAutoresCoincidentes cuenta el nmero de autores coincidentes
a travs del cdigo siguiente:
textoSql = "SELECT COUNT(*) AS LaCuenta " & _
"FROM Autor WHERE Apellido LIKE " & _
DBText(Trim(RegistroApellido.Text))
If (Trim(RegistroNombre.Text) <> "") Then
textoSql &= " And Nombre LIKE " & _
TextoBD(MVB.Left(Trim( _
RegistroNombre.Text), 1) & "%")
End If
cuentaCoincidencias = CInt(EjecutarSQLRegresar(textoSql))
Al establecer la propiedad e.Handled en True se evita que Visual haga algo ms (mucho)
con la tecla ingresada. Es una manera rpida y fcil de disponer de un tecleo de entradas
del usuario.
CodigoGrupoCliente.vb
Este formulario edita registros de la tabla CodigoGrupoCliente.
CodigoSerie.vb
Este editor administra registros en la tabla CodigoSerie. Ya mencion la manera en que
los nombres de serie y las palabras clave estn subordinados a elementos con nombre. Pero
tambin tiene sentido para m proporcionar administracin directa de nombre de series,
en caso de que quiera construir una lista comn antes de agregar artculos individuales de
la biblioteca. As que este formulario realiza una tarea doble: puede acceder a l median-
te el editor estndar de registros ListaRegistrosEditados, y tambin se usa desde un
elemento con nombre especificado a travs del formulario an no agregado ArticuloCon-
Nombre.
Cuando se editan nombres de serie especficos de artculos, el usuario obtiene primero un
nombre de serie, al escribirlo. Como no quiere que el usuario tenga que escribir de nuevo
los nombre de serie en este formulario de editor, quiero pasar el nombre de serie en el for-
mulario CodigoSerie, pero ninguno de los mtodos pblicos sobrescritos son compatibles
con esto. De modo que necesitar agregar un nuevo mtodo que acepte el nombre escrito.
El miembro AgregarRegistro ya sobrescribe la funcin base del mismo nombre.
Public Overrides Function AgregarRegistro(
) As Integer
' ----- Agregar un nuevo registro.
IDActivo = -1
PrepararCamposFormulario()
Me.ShowDialog()
If (Me.DialogResult = Windows.Forms. _
DialogResult.OK) Then _
Return IDActivo Else Return -1
End Function
Agreguemos una sobrecarga a esta funcin que incluye un argumento de cadena. El llamador
pasar el texto originalmente escrito al argumento. Lo asignare a la propiedad Text del con-
trol RecordFullName, para que se muestre apropiadamente cuando se abre el formulario.
Proyecto | 353
S, podramos haber usado algn nombre distinto de AgregarRegistro para esta funcin y
evitado agregar una sobrecarga. Pero es agradable mantener la consistencia de las cosas.
Festivos.vb
Este formulario administra los registros de la tabla Festivo. En un captulo posterior, agre-
gar una cach de das festivos dentro del programa para rpido acceso.
Cliente.vb
El formulario Cliente proporciona servicios de edicin para registros en la tabla Cliente,
y aparece en la figura 12-7.
Figura 12-7. La mayor parte del formulario Cliente (se oculta la ficha de detalles).
Aunque este formulario tiene un aspecto muy complejo, est integrado casi por completo
por cdigo que hemos visto en otros formularios. Ms all de las sobreescrituras estndar
de los miembros de FormularioCodigoBase, este formulario incluye soporte a rastreo de
cdigo de barras prestado del formulario CopiaArticulo, la lgica de contrasea prestada
del formulario NombreUsuario, y cdigo de asignacin de nombres similar al usado en el
formulario Autor.
Inclu un botn Administrar artculos de cliente el formulario, pero no agregaremos su lgi-
ca hasta un captulo posterior. Una funcin pblica adicional, EditarRegistroLimitado,
se vuelve importante en este momento.
Editor.vb
El formulario Editor permite al usuario editar los registros de la tabla Editor. Es un for-
mulario muy simple, con slo dos campos de entrada de datos. Un campo Estatus indica
cuntos registros ArticuloConNombre vinculan a este editor. Aparece un pequeo botn a
la derecha del campo de entrada de texto para el sitio Web del editor. ste es el botn
mostrarme el sitio Web, y cuando se hace clic en l, se trae la pgina Web proporcionada
en el explorador predeterminado del usuario. Para habilitar este botn, agregue el siguiente
cdigo al manejador de eventos Click del botn MostrarWeb.
ValorSistema.vb
Este editor de cdigo maneja elementos de la tabla ValorSistema. Aunque lo conectare-
mos con un vnculo en el formulario Biblioteca en este captulo, cambiaremos este mtodo
de acceso en un captulo posterior.
Proyecto | 355
Las otras cuatro fichas (Autores/nombres, Temas, Palabras clave y Copias) administran registros
subordinados. El cdigo es muy consistente entre las cuatro fichas diferentes, de modo que limi-
tar los comentarios a la ficha Autores/nombres (vase la figura 12-9).
Los controles de esta ficha son muy similares a los del formulario ListaRegistrosEditados;
existen para administrar un conjunto de registros en una tabla. En este caso, la tabla AutorAr-
ticulo. Para conocer la lista de presentacin, eleg usar un control ListView en lugar de uno
ListBox estndar. Al establecer en Details la propiedad View, y en True el campo FullRow-
Select del control ListView, y modificar su coleccin Columns (vase la figura 12-10), puede
convertirla rpidamente en un cuadro de lista de varias columnas.
Cuando agregue un elemento a la lista, tambin tiene que agregar subelementos para hacer que
cualquier cosa aparezca en todo, excepto la primera columna.
Dim nuevoArticulo As Windows.Forms.ListViewItem = _
ListaAutores.Items.Add("John Smith")
nuevoArticulo.SubItems.Add("Ilustrador")
Proyecto | 357
registro principal, y sin un registro principal, no hay un nmero de ID principal. Si revisa cada una
de las rutinas del botn Agregar en este formulario, encontrar cdigo como el siguiente:
' ----- El registro debe guardarse primero.
If (IDActivo = -1) Then
' ----- Confirmar con el usuario.
If (MsgBox("El artculo debe guardarse primero en la base " & _
"de datos antes de que pueda agregarse la palabra clave. " & _
"Le gustara guardar el registro ahora?", _
MsgBoxStyle.YesNo Or MsgBoxStyle.Question, _
TituloPrograma) <> MsgBoxResult.Yes) Then Return
Esta marca se limpia cuando el formulario se abre por primera vez, pero se establece en True
cada vez que cambia un registro subordinado. Las funciones sobrescritas AddRecord y EditRe-
cord del formulario ArticuloConNombre revisa esta marca antes de regresar al formulario que
llama.
If (Me.DialogResult = Windows.Forms.DialogResult.OK) Or _
(SesionGuardada = True) Then Return IDActivo Else Return -1
Cada uno de los manejadores de eventos LinkClicked es casi una imagen de espejo del otro,
excepto por unas cuantos nombres de instancia de objetos por aqu y por all. He aqu el cdigo
que maneja un clic en la etiqueta de vnculo del editor:
Private Sub AdminVinculoEditores_LinkClicked( _
ByVal sender As System.Object, ByVal e As _
System.Windows.Forms.LinkLabelLinkClickedEventArgs) _
Handles AdminVinculoEditores.LinkClicked
' ----- Asegurar que el usuario tiene permitido hacer esto.
If (PerfilSeguridad(SeguridadBiblioteca.AdministrarEditores) = _
False) Then
MsgBox(MensajeNoAutorizado, MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If
Proyecto | 359
Despus de hacer una rpida revisin de seguridad, el cdigo llama al formulario estndar Lis-
taRegistrosEditados, pasndole una instancia del editor de registro que habr de usar.
Hay an unos cuantos vnculos inactivos en el panel Administracin que habilitaremos en ca-
ptulos posteriores.
En un captulo futuro, agregaremos un mtodo ms amigable con el usuario para actualizar esta
ubicacin predeterminada.
Hablando de esto ltimo, estamos por ingresar al mundo no amigable con el usuario, pero s con
la lgica de los datos de texto estructurados: XML.
Debido a que las computadoras son computadoras y las personas son personas, por lo general
tienen necesidades diferentes cuando se trata de poner los datos en un formato til. XML es un
intento de organizar datos en una estructura que sea til para la gente y para el software.
XML se ha puesto de moda en aos recientes, pero sus races son muy antiguas. Se deriva de
SGML (Standard Generalized Markup Language, lenguaje estndar de marcado generalizado),
como HTML (son primos!). SGML, a su vez, proviene de GML (Generalized Markup Lan-
guage, lenguaje de marcado generalizado), un metalenguaje (un lenguaje que describe a otro)
diseado por IBM en la dcada de 1960. As que culpe a IBM si quiere, pero de todos modos
estar en contacto regular con XML mientras desarrolla aplicaciones .NET.
Tambin podra decirlo desde el principio: amar a XML, o lo odiar. Pero tal vez har ambas
cosas. Se trata de una bestia extraa, este XML, como lo esperara de cualquier acrnimo que
toma letras de la parte intermedia de las palabras que representa (eXtensible Markup Langua-
ge, lenguaje extensible de marcado). XML representa un alfabeto de tecnologas de manipula-
cin de datos, un alfabeto que, extraamente, tiene siete X. Pero basta de bromas; extendamos
nuestra comprensin de esta tecnologa bsica de .NET.
Qu es XML?
XML no es ms que un formato de datos que es legible para los seres humanos y para la m-
quina. Alguna vez ha tratado de abrir un documento de Microsoft Word en el Bloc de notas?
Buena suerte (vase la figura 13-1). Aunque podra distinguir fcilmente el texto principal
del documento, la mayor parte de lo que ve son jeroglficos. Eso se debe a que se trata de un
formato binario de propietario. Es de propietario porque, francamente, no debe estar hurgando
all. Para eso est Microsoft Word. Y es binario, porque puede almacenar de manera conve-
niente una gran cantidad de informacin en poco espacio de disco. Con este tipo de archivos,
puedo almacenar mis datos de la manera en que lo prefiera. En realidad, puedo escribir mis
datos de manera grandiosa y no darle permiso a nadie para verlos, porque es mo, mo, todo
mo.
361
Los archivos binarios son estupendos para almacenar cualquier tipo de datos: nmeros, cadenas,
imgenes cifradas en base-64, flujos de plticas en red, cualquier cosa. El problema es que, a
menos que sepa la estructura exacta que us para escribirlo, hay pocas posibilidades de poder
recuperar sus datos. Esto es bueno si su objetivo es la discrecin, pero si alguna vez necesita
compartir esos datos con otra persona o programa, o peor an, depurar la salida de su programa
errante, tendr problemas. Si un solo byte se altera, todo el archivo podra quedar inutilizado.
Existen, por supuesto, otras maneras de almacenar sus datos. En el caso de archivos que almace-
nan registros de datos, los archivos delimitados por comas y CSV (comma-separated value, valor
separado por comas), proporcionan un medio de transferencia conveniente, en un formato ms
amigable para los seres humanos. Por ejemplo, considere estos datos de la base de datos de ejem-
plo Northwind Traders, almacenada como valores separados por comas:
IdProductoo,NombreProductoo,Idproveedor,Categora,CostoUnitario,Disponible
"1","Chai","652","Bebidas","$18.00","Si"
"2","Chang","9874","Bebidas","$19.00","No"
"3","Jarabe de anis","9874","Condimentos","Descuento","Si"
Ahora est mejor. Es muy fcil comprender estos datos. Cada pieza de datos est agrupada por
comas, y la primera fila indica lo que contiene cada columna. Y la mejor parte es que muchos
programas ya saben leer archivos en este formato. Si guarda estos datos en un archivo de texto con
una extensin .csv y la abre en Microsoft Excel, los datos aparecen automticamente en columnas.
Pero podra estar mejor. Por ejemplo, qu significan esos valores 652 y 9874? Y es correcto
que el costo unitario del Jarabe de ans sea Descuento? Seguro, puedo cargar estos datos en
Qu es XML? | 363
La Regla de XML
Antes de que revisemos algn XML real, necesita conocer La Regla. Debe obedecer La Regla con
cada pieza de texto XML que escriba.
LA REGLA
Si lo abre, cirrelo.
Eso es todo. No la olvide. Obedzcala. Viva con ella. Ms adelante le explicar lo que significa.
Hey, no dije que iba a ser interesante. Como le mencion antes, son slo datos, y para colmo, sin
acentos, pero son datos tiles, y he aqu por qu:
Se trata obviamente de XML
Esto queda claro desde la primera lnea, que siempre empieza con <?xml . . . Esta lnea tam-
bin indica el nmero de versin de XML, que le dice a las rutinas de procesamiento de XML
(analizadores sintcticos) que ajusten el comportamiento, si es necesario. Eso es previsin.
Est estructurado
XML es una estructura de datos jerrquica. Es decir, puede tener elementos de datos in-
sertados dentro de otros elementos de datos a cualquier profundidad que quiera. Todos
los elementos estn rodeados por un conjunto de etiquetas. En este ejemplo, las etiquetas
son hola, alli, mundo, cuentaTotal, y adios. Las etiquetas siempre aparecen dentro de
< parntesis angulares >, y siempre lo hacen en parejas, como en <hola>...</hola>. (Aqu
es donde se aplica La regla: Si lo abre, cirrelo.) No olvide la diagonal (/) justo antes del
nombre de la etiqueta en el parntesis de cierre. Esta sintaxis le permite organizar sus datos
en unidades con nombre especficamente organizadas. En el caso de pares de etiquetas que
no tienen nada entre ellas, puede usar la sintaxis corta <nombreetiqueta />, como lo hice
con la etiqueta adios. Por cierto, las etiquetas XML son sensibles al uso de maysculas y
minsculas, de modo que escriba con cuidado.
Es legible
Es legible para los seres humanos, gracias a todos los espacios en blanco, aunque podra
eliminarlos y an tener XML. Tambin es legible para el equipo de cmputo, debido al uso
consistente de etiquetas.
Es una sola unidad de datos
Todos los archivos XML tienen un solo elemento raz en que deben aparecer todos los dems
elementos. En el ejemplo, <hola> es el elemento raz. Una vez que se cierra (mediante su
etiqueta de cierre) no puede agregar elementos adicionales. Nada. Nunca.
Al mover los datos a XML se ha aumentado mucho el tamao del contenido. Pero con un
aumento en el tamao viene uno en el valor de procesamiento. Yo pude obtener de inmediato
algunos beneficios de la estructura jerrquica de XML. En los datos originales, proveedor
era slo otra columna. Pero en la versin de XML, todos los datos estn ahora agrupados en
secciones de proveedor, lo que tiene sentido (al menos si as es como estaba planeando usar
los datos).
Guarde todo ese hermoso texto XML en un archivo de su escritorio como hola.xml. A continua-
cin, ponga la siguiente secuencia de comandos XSLT en otro archivo de su escritorio llamado
hola.xsl. (Observe que divid una lnea con un marcador especial para que el contenido quepa en
este libro. Por favor, no divida la lista separada por comas en esa lnea en el archivo.)
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:text>
IdProducto,NombreProducto,IdProveedor,Categoria,
<smbolo>CostoUnitario,Disponible
</xsl:text>
<BR/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="proveedor">
<xsl:variable name="IdSup" select="@ID"/>
<xsl:for-each select="producto">
"<xsl:value-of select="@ID"/>",
"<xsl:value-of select="nombreProducto"/>",
"<xsl:value-of select="$IdSup"/>",
"<xsl:value-of select="categoria"/>",
"<xsl:choose>
Le dije que era difcil de usar y an ms difcil de revisar. Muy bien, pasemos al espectculo.
Tengo Internet Explorer instalado en mi sistema, pero esto debe funcionar con la mayor parte de
los navegadores. Abra el archivo hola.xml en su navegador, y sorpresa!, debe aparecer el siguiente
texto hermosamente formado:
IdProducto,NombreProducto,IdProveedor,Categoria,CostoUnitario,Disponible
"1", "Chai", "652", "Bebidas", " $18.00", "Si"
"2", "Chang", "9874", "Bebidas", " $19.00", "No"
"3", "Jarabe de anis", "9874", "Condimentos", "Descuento", "Si"
Ahora es ms legible. XML y XSLT juntos han hecho posible este avance en la tecnologa de los datos.
(Hice un poco de trampa en este ejemplo. Notar las entradas <BR/> en la secuencia de comandos
XSLT que no aparecen en la salida final. Lo agregu para que aparecieran de manera correcta en su
explorador.) En serio, aunque pude generar un conjunto de datos separados por comas con XSLT, las
tareas ms comunes para XSLT incluyen la generacin de HTML formado agradablemente con base
en los datos XML, o la generacin de un nuevo documento XML con una vista alterna especfica
de los datos originales. Cmo funciona? En esencia, los elementos <xsl:template> le indican al
analizador sintctico que busque etiquetas en el documento XML que coincidan con algn patrn
(como proveedor). Cuando lo encuentra, aplica todo lo que se encuentra dentro de las etiquetas
<xsl:template> a la etiqueta XML correspondiente y su contenido. El patrn especificado en los
atributos coincidentes usa una tecnologa XML llamada XPath, un sistema para buscar genrica-
mente etiquetas que coinciden dentro de su documento XML.
Suena confuso? Bueno, lo es, y no deje que empiece a explicar todo lo que me tom escribir
esa corta secuencia de comandos XSLT. La creacin de secuencias de comandos XSLT est,
dichosamente, ms all del alcance de este libro. Por supuesto, hay herramientas que facilitan
el trabajo. Pero XSLT slo es til si los datos XML se manipulan de manera correcta. Podra
escribir una transformacin de XSL para reportar las inconsistencias de los datos encontradas
en un documento XML, pero no funcionar si alguna de las etiquetas de su documento est
mal escrita u organizada de manera inconsistente. Para eso, necesita otro avance en la tecnologa
XML: XSD.
Esquemas XML
XSD (XML Structure Definitions, definiciones de estructura XML) le permite definir el esquema
(el lenguaje o vocabulario) de su documento XML particular. Recuerde que XML es un estndar
genrico muy abierto; puede definir las etiquetas de la manera que quiera y a nadie le preocupa-
r, al menos hasta que tenga que procesar las etiquetas con su software. Si no son correctas, es
a esto:
<?xml version="1.0"?>
<listaProductos xmlns="ListaProductosSimple"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="hola.xsd">
Estas directivas le indican al analizador sintctico XML que busque el esquema en hola.xsd.
Tambin definen un espacio de nombres; se explicar ms sobre esto en prrafos posteriores. El
archivo hola.xsd contiene el siguiente esquema:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="ListaProductosSimple">
<xs:element name="listaProductos" type="ListaTiposProducto"/>
<xs:complexType name="ListaTiposProducto">
<xs:sequence>
<xs:element name="proveedor" type="TipoProveedor"
maxOccurs="desunido"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TipoProveedor">
<xs:sequence>
<xs:element name="producto" type="TipoProducto"
maxOccurs="desunido"/>
</xs:sequence>
<xs:attribute name="ID" type="xs:integer"/>
<xs:attribute name="NombreCompleto" type="xs:string"/>
</xs:complexType>
<xs:complexType name="TipoProducto">
<xs:sequence>
<xs:element name="nombreProducto" type="xs:string"/>
<xs:element name="categoria" type="xs:string"/>
<xs:element name="costoUnitario" type="xs:decimal"/>
</xs:sequence>
<xs:attribute name="ID" type="xs:integer"/>
Se ve horrible, o no? En realidad, es ms sencillo que XSLT. En esencia, el esquema dice que cada
elemento (o etiqueta o nodo) en mi documento XML, he aqu los subelementos y atributos
que contienen y el tipo de datos de cada uno. Incluso puede crear sus propios tipos de datos (en
realidad, factores limitantes en los tipos de datos existentes), como hice con el tipo de datos Tipo-
SiONo, que limita el valor relacionado a las cadenas Si y No.
Puede revisar el archivo XML con el esquema XSD adjunto en su explorador, pero no sera tan
interesante. Slo le muestra el XML. Pero los esquemas sern tiles cuando necesite evaluar la
calidad de los datos XML que entran en sus aplicaciones de software de fuentes externas.
Todos los datos son iguales, pero las etiquetas son diferentes. Este tipo de documento sera in-
compatible con software escrito para funcionar con nuestro documento original. Si se ejecuta
el documento a travs de nuestro XSD, nos indicara rpidamente que tenemos un conjunto de
datos falso, pero sera ms agradable si algo nos lo indica desde el principio. Ingrese espacios
de nombres. Los espacios de nombres proporcionan un mtodo conveniente para decir: Esta
etiqueta particular en el documento XML usa este lenguaje definido por XSD. Observe el ini-
cio del esquema XSD mostrado antes:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
Esta lnea configura un espacio de nombres llamado xs al usar el atributo xmlns. (La parte :xs
le indica a XML lo que quiere que sea su espacio de nombres.) El valor del atributo es un iden-
tificador uniforme de recursos (URI, Uniform Resource Identifier), slo que debe ser un valor
En el caso de archivos XML bsicos que slo sern usados por su programa, tal vez no necesite
preocuparse con los espacios de nombres. En realidad resulta prctico cuando est creando datos
XML que usan algn estndar pblico. Tambin hay casos donde un solo archivo XML podra
contener datos relacionados con dos o ms usos distintivos de XML. En este caso, diferentes
partes de su archivo XML podran hacer referencia a espacios de nombres diferentes.
Al igual que con otras partes del mundo XML, XSD y los espacios de nombres no son tan fciles de
usar, pero resultan flexibles y poderosos. Como siempre, hay herramientas, incluidas herramientas
de Visual Studio, que le permiten construir todo esto sin tener que pensar en los detalles.
Como lo seguir diciendo, XML slo son datos, y si su programa y sus datos no se comprenden entre
s, tal vez sera adecuado regresar al cincel y la piedra. XML y sus tecnologas relacionadas proporcio-
nan un mtodo para ayudarle a asegurar que sus datos estn listos para usarlos en su aplicacin.
System.Xml
La principal coleccin de clases relacionadas con XML al viejo estilo.
System.Xml.Linq
Las clases que integran XML con tecnologas LINQ. sta es la nueva manera de la que
hablar ms tarde.
Su documento est integrado por declaraciones (esa cosa <?xml...?> en la parte superior),
elementos de datos (todas las etiquetas especficas de su documento), atributos (dentro de cada
etiqueta de elemento inicial) y comentarios. Estn representadas por las clases XmlDeclara-
tion, XmlElement, XmlAttribute y XmlCommment, respectivamente. Juntas, a estas cuatro
unidades principales de su documento se les denomina nodos, representados genricamente por
la clase XmlNode. (Las cuatro clases especficas heredan de la clase XmlNode ms bsica.) Cuando
construya un documento XML a mano en memoria, usar clases individuales como XmlEle-
ment. Ms adelante, cuando necesite rastrear un documento existente, ser ms fcil de usar la
clase XmlNode genrica.
Construyamos un subconjunto de los datos de producto de nuestro ejemplo XML.
<?xml version="1.0"?>
<listaProductos>
<!--Actualmente vendemos estos articulos. -->
<proveedor ID="652" NombreCompleto="Bebidas R Us">
<producto ID="1" disponible="Si">
<nombreProducto>Chai</nombreProducto>
<categoria>Bebidas</categoria>
<costoUnitario>18.00</costoUnitario>
</producto>
</proveedor>
</listaProductos>
valorProducto = productos.CreateElement("nombreProducto")
valorProducto.InnerText = "Chai"
producto.AppendChild(valorProducto)
valorProducto = productos.CreateElement("categoria")
valorProducto.InnerText = "Bebidas"
producto.AppendChild(valorProducto)
valorProducto = productos.CreateElement("costoUnitario")
valorProducto.InnerText = "18.00"
producto.AppendChild(valorProducto)
Realmente funciona, tambin. Para probarlo, ponga este cdigo en el evento Click de un botn
y termnelo con la siguiente lnea:
productos.Save("c:\productos.xml")
Ejecute el programa y vea el archivo c:\productos.xml para ver los datos de producto de XML.
Hay muchas maneras diferentes de usar las clases XML para crear un documento XML en me-
moria. Por ejemplo, aunque us el mtodo SetAttribute para agregar atributos a los nodos
Bueno, esto es agradable y todo, pero qu pasa si tiene algn XML en un archivo, y slo quiere car-
garlo en un objeto XmlDocument? Simplemente use el mtodo Load del objeto XmlDocument.
Dim productos As XmlDocument
productos = New XmlDocument
productos.Load("c:\productos.xml")
Para los casos en que slo quiera leer o escribir XML en un archivo, y no se preocupe mucho por ma-
nipularlo en la memoria, las clases XmlTextReader y XmlTextWriter le permiten leer y escribir
rpidamente datos XML mediante un flujo de texto. Pero si quiere hacer algo con los datos XML en
su programa, los mtodos Load y Save del objeto XmlDocument son una mejor opcin.
Para conocer una seleccin ms compleja de nodos dentro del documento, el espacio de nom-
bres System.Xml.XPath implementa el lenguaje de bsqueda XPath, que le da una mayor
flexibilidad en la localizacin de elementos. La documentacin de Visual Studio describe los
mtodos y la sintaxis de bsqueda usada con estas clases.
Verificacin de esquema
Un objeto XmlDocument puede incluir cualquier tipo de contenido XML al azar, pero vlido,
aunque tambin puede verificar el documento contra un esquema XSD. Si su documento XML
alude a un esquema XSD, incluye un DTD o usa XDR (esquemas XML Data Reduced, reduci-
dos de datos XML, similares a XSD), un XmlReader, cuando se configur con el XmlReader-
Settings apropiado, comparar apropiadamente sus datos XML contra las reglas definidas, y
lanzar una excepcin si hay un problema.
XML Transformations
Las transformaciones de XSL Transformations no son ms difciles que cualquier otra manipula-
cin de XML. As como hay muchas maneras de obtener datos de origen XML (desde un archi-
vo, construyendo uno a mano con XmlDocument, etc.), hay muchas maneras de transformar los
datos. Si slo quiere ir de un archivo de entrada a uno de salida, el siguiente cdigo proporciona
un mtodo rpido y eficiente. Usa una instancia de System.Xml.Xsl.XslCompiledTrans-
form para hacer magia.
' ----- Arriba: Imports System.Xml.Xsl
Dim xslTrans As XslCompiledTransform
Qu tal eso? Excepto por la primera lnea de declaracin, el contenido es idntico al XML final.
La nueva caracterstica Literales de XML facilita mucho la construccin de documentos XML. El
contenido se almacena en el nuevo objeto XDocument, parte del espacio de nombres System.
Xml.Linq. Si slo quiere almacenar una seccin de XML en lugar de todo el documento, use,
en cambio, la clase XElement.
Dim seccionProducto As System.Xml.Linq.XElement = _
<producto ID="1" disponible="Si">
<nombreProducto>Chai</nombreProducto>
<categoria>Bebidas</categoria>
<costoUnitario>18.00</costoUnitario>
</producto>
Si tiene habilitadas las inferencias de tipo en su programa (Option Infer On), ni siquiera ne-
cesita indicarle a Visual Basic si es un XElement o un XDocument.
Dim seccionProducto = _
<producto ID="1" disponible="Si">
<nombreProducto>Chai</nombreProducto>
<categoria>Bebidas</categoria>
<costoUnitario>18.00</costoUnitario>
</producto>
Al igual que la clase XmlDocument, la clase XDocument incluye mtodos Load y Save para
administrar XML basado en archivos.
Por supuesto, para generar un catlogo completo de productos, necesita escribir mucho. En el
captulo 17, presentar algunas maneras adicionales de incrustar expresiones XML con tablas de
datos completas.
Eje de atributos
Puede acceder a cualquier atributo de un elemento al tratar el nombre del atributo como un
nombre de miembro, antecediendo el nombre del atributo con el carcter @:
valorAtributo = elementoPrimario.@nombreAtributo
El siguiente bloque de cdigo rastrea la lista de productos diseada antes en este captulo, des-
plegando el nmero de ID y el nombre de cada producto en la consola:
For Each unProducto In productosCompletos...<producto>
Console.WriteLine(unProducto.@ID & ": " & _
unProducto.<nombreProducto>.Value)
Next unProducto
Este cdigo utiliza los tres estilos de eje. El bucle For Each...Next revisa todas las entradas
<producto> coincidentes al usar un eje elemento descendente-miembro. En cada elemento de
producto coincidente, el cdigo accede al atributo ID empleando un eje de atributos, y obtiene
el nombre del producto usando un eje elemento secundario-miembro, junto con la propiedad
Value del elemento secundario devuelto. La salida tiene este aspecto:
Para conocer maneras ms avanzadas de rastrear contenido XML y seleccionar elementos secun-
darios con base en criterios complejos, consulte el captulo 17.
Tambin puede definir el espacio de nombres, la parte xmlns, al usar una variacin de la instruc-
cin Imports de Visual Basic.
Imports <xmlns:menu="http://www.timaki.com/menu">
...despues...
Dim articulosAlimenticios = _
<?xml version="1.0"?>
<menu:articulos>
...etcetera...
Visual Basic an insertar la definicin xmlns en el lugar correcto del contenido XML. En
realidad est almacenado como un objeto XNamespace distintivo dentro de XDocument o
XElement. Para generar un objeto XNamespace para su propio uso, Visual Basic incluye una
nueva funcin GetXmlNamespace.
Dim soloespacioNombres = GetXmlNamespace(menu)
Resumen
Hay una gran cantidad de caractersticas tiles en los varios espacios de nombres de System.
Xml y puede administrar datos complejos en maneras efectivas. No siempre es la manera ms
eficiente de administrar datos, pero si ha estructurados datos jerrquicos, puede ser el mtodo
ms directo y claro.
Proyecto
El administrador del sistema Biblioteca querr ver estadsticas e informacin de un vistazo, o
ejecutar informes que proporcionen un resumen significativo, o vistas detalladas de datos del
sistema. Aunque como programador podra tratar de aadir cada tipo concebible de informe
que el usuario necesite, la experiencia me ha enseado que eso no es posible. Los usuarios
siempre quieren la luna, por lo general en la forma de varios extraos y esotricos informes que
s que usarn una vez y nunca volvern a ver (aunque llamarn una vez al ao pidiendo que se
vuelva a escribir el mismo tipo de informe). No me gusta volver a compilar y relanzar toda la
aplicacin cada vez que un usuario necesite un nuevo informe. En cambio, mantengo los in-
formes fuera de la aplicacin, almacenados como programas separados. Luego, a partir de un
formulario de la aplicacin principal, pongo a su disposicin esos informes externos en una
bonita y conveniente lista.
Para implementar esta caracterstica genrica, uso el archivo de configuracin de informes, un
simple archivo XML que contiene informacin sobre los informes disponibles, y la manera
de ejecutarlos. Quiero que mi lista de seleccin tenga elementos con sangra para que puedan
agrupar los informes de manera visible, para mayor conveniencia. Para esto, crear mi archivo
XML en una jerarqua de profundidad ilimitada, y cada nivel representar un nivel adicional de
sangra desplegada. Por ejemplo, digamos que quiere el siguiente esquema de informes (con los
ttulos de grupo de informes en negritas):
Informes de detalle
Informes diarios
Informes mensuales
Valor mensual
Inventario mensual
Proyecto | 379
Por supuesto, esto es XML muy simplificado (sin mencionar que no cumple con los requisitos).
Adems de la jerarqua, tambin quiero incluir soporte para varios mtodos de informes. Para
simplificar las cosas, el Proyecto Biblioteca incluir tres tipos de informes:
Informes integrados
La aplicacin incluye una cantidad limitada de informes que estn integrados de manera
permanente en la aplicacin (el ensamblado) principal. Los informes estn numerados a
partir del 1, y en este momento tengo cinco informes en mente. El diseador del archivo
de configuracin XML puede elegir si los incluye en el despliegue de los informes o no con
slo incluirlos en el archivo. En ausencia de un archivo de configuracin, estos informes
aparecern en la lista como opcin predeterminada. Adems del nmero de informe (1 a 5),
cada entrada tiene un texto de despliegue y una descripcin larga.
Informes de la aplicacin
Estos informes son archivos EXE separados y distintos, y se inician mediante los mtodos
de inicio estndar. Cada entrada incluye un texto de despliegue, la ruta completa a la apli-
cacin, argumentos opcionales, una marca que se pasar para la identidad del usuario que
inicia el informe, y una descripcin larga.
Informes de URL
Estos informes son simples llamadas a pginas Web, o cualquier otro URL vlido. Por ejemplo,
podra incluir una entrada de informe que tenga un mailto: al escritorio de ayuda de la orga-
nizacin. Cada entrada incluye el texto de despliegue, el propio URL y una descripcin larga.
Las actividades del proyecto de este captulo incluyen la codificacin y la documentacin del
nuevo recurso externo (el formato de archivo XML).
ACCESO AL PROYECTO
Cargue el proyecto Cap13 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap13 (Final) cdigo.
Proyecto | 381
En este mismo archivo, agregue los miembros de la clase ElementoInforme. Esta clase contiene
toda la informacin que necesitamos para ejecutar informes cargados del archivo de configuracin.
Proyecto | 383
Ajuste el orden de tabulacin de los nuevos controles al seleccionar el formulario, y luego usar el
comando de men Ver Orden de tabulacin.
Aunque tal vez el administrador ha asignado nombres tiles a cada informe, la suavidad de cada
nombre an puede confundir al usuario. Cada informe incluye una descripcin completa opcio-
nal. A medida que el usuario seleccione informes de la lista, un manejador de eventos actualiza
la etiqueta DescripcionCompleta que se encuentra justo debajo de la lista principal. Agregue
este miembro de controlador de eventos a la clase.
Proyecto | 385
Debido a que el archivo de configuracin del informe permite anidar grupos de informes en
cualquier nivel, necesitamos usar una rutina recursiva para descender de manera repetida a cada
nivel sucesivo. La rutina CargarGrupoInforme, llamada por ActualizarListaInformes,
agrega todos los elementos y grupos de informes dentro de un grupo de informes inicial. Es
llamada al principio desde el punto de referencia del elemento raz <listaInformes>. Cada
vez que encuentra un elemento secundario <grupoInformes> se llama a s mismo una vez ms,
pero esta vez a partir del punto de referencia del elemento secundario <grupoInformes>.
Proyecto | 387
ErrorHandler:
ErrorGeneral("SeleccionarInforme.CargarGrupoInforme", _
Err.GetException( ))
Resume Next
End Sub
Agregue el evento Load del formulario, que carga el contenido del archivo de configuracin.
Proyecto | 389
ErrorHandler:
ErrorGeneral("SeleccionarInforme.AccEjecutar_Click", _
Err.GetException())
Resume Next
End Sub
Para los informes externos, el manejador de eventos llama al mtodo Process.Start. Este
mtodo sorprendente acepta una expresin estndar de lnea de comandos o cualquier URL o
direccin de pgina Web vlida.
Ahora que tenemos un firme conocimiento del mundo de XML, dejemos que Visual Basic haga
todo el trabajo difcil de manipularlo para fines de configuracin de la aplicacin.
Proyecto | 391
Hace casi un siglo, el presidente Abraham Lincoln empez su famoso discurso de Gettysburg
con Hace casi un siglo Por qu esta referencia potica a la fundacin de Estados Unidos
hace 87 aos? Pudo haber empezado el discurso diciendo: La ltima semana, estaba hablando
con miembros de mi gabinete o an Estos tres soldados confederados entraron en un bar
Pero se apeg a la ancdota de varias dcadas antes.
Lincoln comprenda que sus escuchas, como seres humanos, tenan una liga con el pasado, un
cario por lo familiar, un amor por los automviles deportivos rpidos y un deseo de ver que se
restauraba la estabilidad de una era anterior. As es la gente. Les gusta la paz, no la guerra. Les
gusta lo establecido, no el cambio. Les gusta comer en la mesa cuando regresan a su casa despus
de un da difcil en la oficina. Les gustan las filas cortas en el parque de diversiones. Les gusta ver
a su equipo favorito de ftbol ganar de vez en cuando.
A la gente le gusta saber que las cosas estn configuradas de una manera que tenga sentido para
ellos, configuradas de una manera que les sea familiar y conocida. Esperan esto en vida y lo
esperan en su software. Por eso, Visual Basic incluye caractersticas que le permiten mantener
configuraciones especficas de usuario y de la aplicacin.
392
El formato de un archivo INI era simple de comprender. Cada archivo inclua secciones con
nombre definidas entre corchetes, como en [fonts]. Cada seccin mantena un conjunto de
pares clave-valor en la forma clave=valor. El formato era lo bastante simple como para que
cualquiera pudiera usar el Bloc de notas para hacer cambios. Ni siquiera era difcil que un pro-
grama escribiera sus propias rutinas de administracin del archivo INI, pero incluirlos en la API
de Windows haca eso mucho ms atractivo.
Pero entonces lleg el amontonamiento. Con tantos programas optando por almacenar sus ar-
chivos de configuracin en una ubicacin central conocida, la carpeta Windows se volvi rpi-
damente el equivalente en archivo de la Gran Estacin Central a las 5:00 p.m. en un viernes. La
velocidad era un problema, tambin, porque el anlisis y la reescritura constante de los archivos
INI consuman recursos preciosos de la CPU.
Microsoft surgi con una solucin: el registro. Esta base de datos de pares clave-valor limpi el
sistema de archivos y trajo mejoras en velocidad a la administracin de la configuracin. Tambin
agreg nuevas configuraciones de seguridad definidas por el administrador para acceder al regis-
tro, y proporcion soporte para los mismos datos de tipo fuertemente delimitados. Pero las carac-
tersticas de la nueva API no fueron las ms intuitivas (aunque Visual Basic s inclua comandos
simples, como GetSetting, que proporcionaba acceso limitado a claves y valores de registro).
El registro llev tecnologa al problema de los valores de configuracin, pero no fue un triunfo
completo. Con tantos vendedores metiendo montones de datos en el registro, el crecimiento
inusual se volvi otra vez un problema. Y como el sistema administraba todo el acceso al registro,
cuanto ms grande era ste, peor era el rendimiento.
El lanzamiento inicial de .NET inclua archivos especficos de la aplicacin, una especie de re-
greso a los das ya pasados del archivo INI. En cierta manera, los archivos app.config y web.
config eran mejores que los archivos INI porque incluan contenido XML estructurado. Pero
haba algo de qu alegrarse. Los archivos INI tenan estructura y poda actualizarlos en el Bloc
de notas. Los archivos de configuracin de .NET eran notablemente difciles de actualizar, ya sea
En tiempo de ejecucin, todos los parmetros especficos del usuario aparecen en el archivo
user.config, almacenado por lo general en C:\Documents and Settings\<usuario>\Configuracin
local\Application Data\<compaia>\<datosaplicacin>\<version>, donde <usuario>
es el nombre de usuario de Windows, <compaia> es el nombre de la compaa guardado en
el ensamblado, <datosaplicacion> es una combinacin de valores que ayudan a diferenciar
las configuraciones basadas en el uso y <version> es la versin en cuatro partes del nmero
del ensamblado. Al parecer, es un lugar difcil para almacenar configuraciones, pero mantiene
las cosas ordenadas. (La ubicacin del archivo user.config es un poco diferente, si despliega una
aplicacin empleando ClickOnce, un mtodo descrito en el captulo 25.)
Tal vez se est preguntando si esto contribuye a la aglomeracin en el disco. S! Cada vez
que sube el nmero de versin de su aplicacin, .NET crea un nuevo archivo de configura-
cin para acompaarlo. Hay una manera de mitigar esto, de alguna manera, pero con discos
duros de 120 GB, nadie se est quejando ms acerca del uso del espacio en disco.
Algunos valores estn centrados en la aplicacin, y se aplican a todos los usuarios de la
aplicacin en una estacin de trabajo particular. Se almacenan en el archivo app.config que
aparece en la misma carpeta que el ejecutable de su ensamblado. Los parmetros aparecen
en una rama de XML llamada <applicationsettings> dentro de este archivo. Los pa-
rmetros concentrados en la aplicacin no pueden ser modificados por la aplicacin; debe
actualizar manualmente el archivo app.config para forzar un cambio.
El sistema de configuracin es un lugar estupendo para almacenar el estado, que son las cosas que
el programa recuerda de la ltima vez que se ejecut, pero que no deben incluirse en el cdigo
fuente.
archivo INI. Puede elegir cualquier tipo .NET vlido para el tipo de datos, aunque los tipos com-
plejos sin sus propios editores personalizados requerirn que establezca su valor mediante cdigo.
Qu sucede cuando agrega un nueva configuracin a un proyecto de Visual Basic? Descubrmoslo.
Agregar dos parmetros a un nuevo proyecto de Windows Forms: un Integer denominado Li
mitePrecaucion, y un System.Drawing.Font llamado FuenteNota (vase la figura 14-2).
Como ya lo sabe, Visual Studio es slo una envoltura amigable con el usuario alrededor de c-
digo .NET, y el panel Configuracin no es diferente. As, los cambios reales ocurren en algn
lugar del cdigo, o ms correctamente, en el cdigo y el archivo Settings.settings. Si elige Mostrar
todos los archivos en el panel Explorador de soluciones, y expande My Proyect seguido por Set-
tings.settings, encontrar que este archivo XML tiene su propio archivo de configuracin fuente
de Visual Basic, Settings.Designer.vb.
Si abre el archivo Settings.Designer.vb, encontrar el siguiente cdigo parcial:
Namespace My
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration. _
ApplicationSettingsBase
<Global.System.Configuration. _
UserScopedSettingAttribute(), _
Global.System.Diagnostics. _
DebuggerNonUserCodeAttribute( ), _
Global.System.Configuration. _
DefaultSettingValueAttribute( _
"Arial, 14.25pt, style=Bold")> _
Public Property FuenteNota() _
As Global.System.Drawing.Font
Get
Return CType(Me("FuenteNota"), _
Global.System.Drawing.Font)
End Get
Set
Me("FuenteNota") = valor
End Set
End Property
End Class
End Namespace
Exclu una gran cantidad de cdigo adicional. Es sorprendente la cantidad de cdigo que Mi-
crosoft carga en atributos preescritos, y en realidad no es posible saber lo que hay dentro. Puedo
adivinar lo que hace el atributo DefaultSettingValueAttribute para cada configuracin
(asigna el valor predeterminado inicial de la configuracin), pero algunos de los dems son mis-
terios. Oh, bueno. Ni siquiera los ancestros tenan respuestas para todo.
Pero el cdigo que permanece es muy claro. Visual Studio genera dos propiedades dentro de la
clase My.MySettings, llamadas (vaya sorpresa) LimitePrecaucion y FuenteNota. He aqu
la entrada de la propiedad para FuenteNota:
Public Property FuenteNota() As Global.System.Drawing.Font
Get
Return CType(Me("FuenteNota"), _
Global.System.Drawing.Font)
End Get
Set
Me("FuenteNota") = valor
End Set
End Property
Cada configuracin contiene atributos o entradas Name, Type, Scope y Valor distintivos, que co-
inciden con las cuatro columnas que aparecieron en el editor de configuraciones de Visual Studio.
My.Settings
Visual Basic crea una instancia de la clase My.MySettings que acabamos de ver, y lo pone a
disposicin como My.Settings. A medida que agrega parmetros a su proyecto, se vuelven
miembros de clase con tipo fuerte de My.Settings. Para acceder a uno, simplemente haga
referencia a l directamente en su cdigo.
MsgBox("La fuente para nota es: " & _
My.Settings.FuenteNota.ToCadena())
(La salida para este cdigo aparece en la figura 14-3.) La My.Settings.FuenteNota es una ins-
tancia real de System.Drawing.Font que puede usar como cualquier otra instancia de Font.
Puede modificar el valor de cualquier configuracin con mbito Usuario, y hacer que el nuevo
valor se preserve para su siguiente uso de la aplicacin (es decir, para el siguiente uso del usuario
actual de la aplicacin).
My.Settings.LimitePrecaucion = 30
Todos los cambios hechos a estos parmetros se guardaron automticamente en los archivos
de configuracin especficos del usuario, como opcin predeterminada. Si no quiere que las
actualizaciones se guarden automticamente, establezca la marca My.Application.SaveMy
SettingsOnExit en False. Luego, cuando est listo para guardar los nuevos valores, use el
mtodo My.Settings.Save.
Las configuraciones vienen en tres deliciosos sabores: predeterminadas, persistentes y actuales. Las
configuraciones predeterminadas son los valores definidos por el programador a travs del editor de
configuraciones de Visual Studio. Las configuraciones persistentes incluyen los cambios guardados
en configuraciones especficas, y las configuraciones predeterminadas son las que nunca han
sido alteradas por el usuario. Las configuraciones actuales incluyen cualquier cambio hecho a las
configuraciones durante la sesin actual, pero an no guardados. Puede jugar con estos estados
usando miembros del objeto My.Settings:
El mtodo Save, como ya se mencion, guarda todas las configuraciones actuales en un
estado persistente.
El mtodo Reload restaura cualquier valor actual con las versiones persistentes.
El mtodo Reset elimina todas las configuraciones actuales y persistentes, y regresa todas
las entradas de configuracin a sus valores predeterminados.
Uno de los aspectos ms extraos es que son especficos de la versin. Si lanza su aplicacin
como versin 1.0.0.0, y luego libera la versin 1.1.0.0, cada usuario perder todos los valores
persistentes anteriores. En realidad, no se perdern, pero se quedarn en la tierra del 1.0.0.0.
Si siempre quiere tener las configuraciones ms actualizadas de acuerdo con las modificaciones
del usuario, tendr que asegurarse de que las configuraciones anteriores tienen la capacidad de
actualizarse cuando se instala una nueva versin. My.Settings incluye un mtodo Upgrade
que hace el trabajo de manera automtica. Pero si el usuario instala una versin ms reciente y
actualiza las configuraciones, hace cambios a esos cdigos y luego llama de nuevo a Upgrade, se
perder cualquier cambio hecho desde la ltima actualizacin.
Para sortear este problema, el cdigo debe actualizar las configuraciones slo cuando aparezca
una nueva versin. La manera ms fcil de hacer esto incluye una configuracin llamada algo
as como SettingsUpgraded y establecerla en False. Revise esta marca antes de llamar a Up
grade. Si un es False, resulta seguro llamar a Upgrade. Una vez que el cdigo actualice la
configuracin, cambie SettingsUpgraded a True.
Esta necesidad de actualizar la configuracin cada vez que se haga el cambio an ms nfimo de cada
versin menor a un ensamblado parece un poco difcil. Pero es necesario dar soporte al objetivo de
.NET de una instalacin completa. El usuario debe tener la capacidad de instalar dos versiones dis-
tintas de su aplicacin en la misma estacin de trabajo, y usar cada una sin interferencia de la otra.
El almacenamiento de las configuraciones especficas de la versin ayuda a lograr este objetivo.
Configuraciones de unin
Aunque el uso y la actualizacin de sus valores de configuracin predeterminados pueden ser
excitantes, an ms excitante es que los campos en su Windows Forms y sus controles relaciona-
dos pueden interactuar interactivamente con los parmetros persistentes. Al unir las propiedades
especficas del formulario y el control al sistema de configuraciones, Visual Basic guarda autom-
ticamente y restaura las preferencias controladas por el usuario dentro de la interfaz de usuario.
Un uso tpico para las configuraciones de unin es hacer que la aplicacin recuerde dnde apa-
reci un formulario particular en la pantalla cuando el programa se ejecutaba por ltima vez.
La propiedad Location del formulario mantiene su posicin en pantalla. El hecho de recordar
este valor de los parmetros requiere dos pasos. En primer lugar, se debe crear una configuracin
de tipo System.Drawing.Point para mantener el valor de ubicacin persistente. En segundo
lugar, se debe indicar en las propiedades del formulario que su valor Location debe persistir
para la nueva entrada de parmetros.
El primer paso se realiza al agregar un parmetro System.Drawing.Point con mbito para
el nuevo usuario en el panel Configuracin, de las propiedades del proyecto. Llammoslo
PosicionFormularioPrincipal y deje el campo Valor en blanco por ahora.
De regreso en el editor del formulario, seleccione el propio objeto del formulario, y luego acceda
al panel Propiedades. Expanda la propiedad (ApplicationSettings) para localizar la subpropie-
dad (PropertyBinding). Al hacer clic en el botn de esta entrada se despliega el cuadro de
dilogo Configuracin de la aplicacin. Este proceso de seleccin aparece en la figura 14-4.
Busque la entrada Location en la lista y elija PosicionFormularioPrincipal como valor. Ahora,
cada vez que ejecute la aplicacin que contiene esta configuracin de unin, el formulario mo-
dificado recordar su ubicacin anterior.
Resumen
Al igual que con XML, el sistema de configuracin de .NET es una de esas caractersticas in-
ternas, tras bambalinas; no deje que el jefe conozca que hace que su programa sea estupendo
para usar, pero sin todas esas cosas llamativas. De manera personal, los encontr un poco difcil
de compartir con mis preciosos archivos INI y de todas, su simplicidad. Pero la automatizacin
adjunta al sistema de configuracin hace que la migracin sea simple.
Proyecto
Por supuesto, agregaremos parmetros al Proyecto Biblioteca en este captulo, pero tambin
regresaremos y empezaremos a usar algunas de esas configuraciones en el cdigo que ingresamos
antes como valores codificados.
Realmente luch por decidir si se usan valores de configuracin con mbito de la aplicacin o
mbito del usuario para algunos de los parmetros que realmente cambian, como la cadena de
conexin de base de datos. Por ltimo, decid usar el rea del usuario para que pudieran modi-
ficarse mediante las caractersticas del programa. Los valores de mbito de la aplicacin son de
slo lectura y slo pueden actualizarse fuera del programa, de modo que sa es la idea. Lo que
se espera con los parmetros del mbito de la aplicacin es que el administrador del sistema los
administre, al usar el Bloc de notas o el archivo XML, o a travs de alguna herramienta adminis-
trativa personalizada. Como no vamos a tomar el tiempo en el proyecto de este libro de escribir
una herramienta de administracin separada, mantendremos todo en el nivel del usuario y per-
mitiremos la modificacin a travs de todo el programa Biblioteca.
ACCESO AL PROYECTO
Cargue el proyecto Cap14 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap14 (Final) cdigo.
Proyecto | 401
Proyecto | 403
Asegrese de escribir los nombres de las configuraciones como aparecen aqu. La aplicacin no
los podr encontrar con nombres escritos de manera incorrecta.
DiasGraciaMulta = 1
Proyecto | 405
' ----- Mostrar u ocultar el boton Iniciar sesion para las configuraciones.
AccIniciarSesion.Visible = Not My.Settings.OcultarInicioSesion
El trabajo significativo de este formulario ocurre en el evento Load cuando la cadena de co-
nexin existente se analiza en los datos del campo de entrada distintivos, y en la rutina
PromptUser, donde se integran las partes.
Hay muchas maneras diferentes en que puede dividir la cadena de conexin en sus partes bsi-
cas. Yo tomo el mtodo bsico divide y conquistars, extrayendo cada componente separado por
dos puntos y signos de igual. He aqu el bloque principal de cdigo del manejador de evento
Load que hace el recorte y la extraccin:
' ----- Cargar los datos existentes.
cadenaConexion = My.Settings.ConexionBD & ""
For contador = 1 To ContarSubCadena(cadenaConexion, ";") + 1
' ----- Cada parte delimitada por comas tiene el formato
' "clave=valor".
unaClave = ObtenerSubCadena(cadenaConexion, ";", contador)
unValor = Trim(ObtenerSubCadena(unaClave, "=", 2))
Proyecto | 407
Unir las partes es menos complicado. He aqu el cdigo de unin de cadenas encontrado en la
rutina PreguntarUsuario:
nuevaConexion = "Data Source=" & Trim(RegistroServidor.Text) & _
";Initial Catalog=" & Trim(RegistroBaseDatos.Text)
If (CInt(CType(RegistroAutentificacion.SelectedItem, _
DatosListaElementos)) = AutentificacionTipoWindows) Then
' ----- Usar seguridad de Windows.
nuevaConexion &= ";Integrated Security=true"
Else
' ----- Usar seguridad de SQL Server.
nuevaConexion &= ";User ID=" & Trim(RegistroUsuario.Text) & _
";Password=" & Trim(RegistroClaveUsuario.Text)
End If
La rutina tambin incluye cdigo similar para cargar una lista de impresoras instaladas.
For Each impresoraInstalada As String En _
PrinterSettings.InstalledPrinters
RegistroLugarImpresora.Items.Add(impresoraInstalada)
Next impresoraInstalada
Proyecto | 409
Varios de los parmetros especifican las ubicaciones de archivos usados por la aplicacin, como
los archivos de ayuda en lnea. El usuario puede escribir la ruta al archivo directamente, o usar
el cuadro de dilogo Abrir archivos para localizar el archivo visualmente. Para desplegar este
cuadro de dilogo he agregado un control OpenFileDialog llamado LocalizarArchivo.
Usarlo es cosa de configurar las diversas propiedades especficas de archivo y llamar al mtodo
Show Dialog. He aqu parte del cdigo incluido en el manejador de eventos AccAyudaBasi
ca_Click usado para localizar el archivo no administrativo en lnea:
' ----- Configurar la estructura del archivo.
LocalizarArchivo.DefaultExt = "chm"
LocalizarArchivo.FileName = RegistroAyudaBasica.Text
LocalizarArchivo.Filter = "Archivos de ayuda (*.chm)|*.chm|" & _
"Todos los archivos (*.*)|*.*"
LocalizarArchivo.FilterIndex = 1
LocalizarArchivo.Title = "Localizar ayuda"
Una vez que el usuario ha hecho los diversos cambios de configuracin, un clic en el botn
Aceptar guarda cada una de las configuraciones en su rea de almacenamiento. He incluido
el cdigo de guardado concentrado en la base de datos en la rutina GuardarDatosFormu
lario. Le permitir agregar el cdigo concentrado en configuraciones, cerca del final de la
rutina.
Proyecto | 411
My.Settings.ConexionBD = ConexionBiblioteca
My.Settings.ConfigInforme = Trim(RegistroLugarConfiguracion.Text)
My.Settings.ArchivoAyuda = Trim(RegistroAyudaBasica.Text)
My.Settings.ArchivoAyudaAdmin = Trim(RegistroAyudaAdmin.Text)
My.Settings.OcultarInicioSesion = OcultarInicioSesion.Checked
My.Settings.UsarRecibos = HabilitarRecibos.Checked
My.Settings.ImpresoraRecibo = Trim(RegistroLugarImpresora.Text)
My.Settings.EnvioRecibo = RegistroEnvioRecibo.Text
Aunque el formulario Mantenimiento proporciona una interfaz amigable con el usuario para
las configuraciones de almacenamiento de base de datos, tal vez recuerde que ya escribi cdigo
para actualizar registros de la tabla ValorSistema mediante el archivo ValorSistema.vb. En el
captulo 12 conectamos ese formulario con el formulario principal, pero vamos a alterar esa
lgica. En primer lugar, agregaremos la llamada al formulario ValorSistema del manejador de
eventos AccTodosLosValores_Click del formulario Mantenimiento.
' ----- Dejar que el usuario edite la lista de valores del sistema.
Dim FormularioRegistros As Biblioteca.ListaRegistrosEditados
Ahora que tenemos disponibles una cadena de conexin configurada por el usuario, la usaremos.
Los cambios que debemos hacer a esta rutina son de alguna manera extensos, de modo que slo
reemplace el contenido existente de la funcin con el cdigo actualizado.
' ----- Conectar con la base de datos. Regresar True si se tiene exito.
Dim cadenaConexion As String
Dim configCambiada As Boolean
Proyecto | 413
TryConnectingAgain:
Proyecto | 415
416
Caracterstica Descripcin
EOF Regresa un Boolean indicando si la posicin actual en el archivo est en el final o lo ha rebasado. Use esta
funcin para determinar cundo dejar de leer los datos existentes de un archivo.
FileAttr Accede a los atributos del archivo establecidos actualmente en un manejador de archivos abierto.
FileClose Cierra un archivo especfico abierto empleando un manejador de archivos.
FileGet Recupera datos estructurados de un archivo y los almacena en un objeto coincidente.
FileGetObject Igual que FileGet, pero con soporte a un tipo de datos ligeramente diferente.
FileOpen Abre un archivo para entrada o salida.
FilePut Escribe un objeto en un archivo de una manera estructurada.
FilePutObject Igual que FilePut, pero con soporte a tipos de datos ligeramente diferentes.
FileWidth Establece el ancho de lnea predeterminado para los archivos de salida de texto formados.
FreeFile Devuelve el siguiente manejador de archivos disponible.
Input Recupera un valor escrito previamente o un archivo empleando Write o WriteLine.
InputString Recupera un nmero especfico de caracteres de un archivo de entrada.
Caracterstica Descripcin
LineInput Devuelve una lnea completa de entrada de un archivo.
Loc Devuelve el byte actual o la ubicacin de registro en el archivo.
Lock Bloquea un archivo o registro especfico en un archivo para que otros no puedan hacer cambios.
LOF Devuelve la longitud de un archivo abierto, en bytes.
Print Enva salida de texto a un archivo.
PrintLine Enva salida de texto a un archivo, que finaliza con un terminador de lnea.
Reset Cierra todos los archivos abierto con manejadores de archivos.
Seek Obtiene o establece la posicin actual en un archivo.
SPC Esta funcin ayuda a formar texto para salida a archivos de texto en columnas.
TAB Esta funcin ayuda a formar texto para salida a archivos de texto en columnas.
Unlock Elimina bloqueos establecidos antes con Lock.
Write Escribe datos en un archivo empleando un formato consistente que puede leerse fcilmente ms adelante.
WriteLine Igual que Write, pero finaliza la salida con un terminador de lnea.
Caractersticas de flujo
Las caractersticas bsicas de un objeto Stream incluyen los mtodos Read y Write que le per-
miten leer o escribir bytes. Mientras los datos se leen de un flujo o se escriben en uno, el objeto
Stream mantiene una posicin actual dentro del flujo que puede ajustar usando el mtodo
Seek, o examinar usando la propiedad Position. La propiedad Length indica el tamao de los
datos legibles. La clase tambin expone variaciones de esas caractersticas bsicas para permitir la
mayor flexibilidad posible.
No todos los flujos dan soporte a todas las caractersticas. Algunos son de slo lectura, construc-
tores slo en sentido directo, no compatibles con escritura o bsqueda. Otros flujos dan soporte
a todas las caractersticas. Las que estarn disponibles para usted dependern del tipo de flujo
que use. Como el propio Stream es abstracto, debe crear una instancia de una de sus clases de-
rivadas. .NET define varios flujos tiles listos para que los use:
Uso de un flujo
El uso de un flujo es simple; en primer lugar, se crea y luego se empieza a leer y escribir bytes a
la izquierda o la derecha. He aqu un cdigo de ejemplo que escrib y que ingresa y extrae datos
de un flujo de memoria. Se basa de manera general en el cdigo que encontrar en la documen-
tacin de MSDN para la clase MemoryStream.
' ----- El flujo, o aqui y alla de nuevo.
Dim posicion As Integer
Dim flujoMem As IO.MemoryStream
Dim caracsOrigen() As Byte
Dim bytesDestino() As Byte
Dim caracsDestino() As Char
Dim comoUnicode As New System.Text.UnicodeEncoding(
)
' ----- Crear un flujo de memoria con espacio para 100 bytes.
flujoMem = New IO.MemoryStream(100)
Try
' ----- Almacenar los datos convertidos en bytes del flujo.
flujoMem.Write(caracsOrigen, 0, caracsOrigen.Length)
' ----- La posicion esta al final de los datos escritos.
' para leer hacia atras, debemos mover el puntero al
' principio de nuevo.
flujoMem.Seek(0, IO.SeekOrigin.Begin)
Se espera que los comentarios hagan ms claro el cdigo. Despus de crear un flujo de memoria,
incluyo un bloque de texto en l y luego lo leo de regreso. (El texto permanece en el flujo; al leer-
lo no lo elimina). En realidad, el flujo de texto es muy simple. La mayor parte del cdigo trata
con conversiones entre bytes y caracteres. Si parece muy complicado, es que lo es.
' ----- Crear un flujo de memoria con espacio para 100 bytes.
flujoMem = New IO.MemoryStream(100)
' ----- Crear un lector para obtener de nuevo los datos de regreso.
paraLectura = New IO.StreamReader(flujoMem, comoUnicode)
Es seguro que el cdigo es un poco ms agradable sin toda esa conversin de cdigo que hace
ms complejo el trabajo. (Podramos simplificarlo an ms al dejar fuera lo de la codificacin
opcional en Unicode.) Por supuesto, todo an se est convirtiendo a bytes bajo la superficie;
el flujo de memoria slo conoce de bytes. Pero StreamWriter y StreamReader nos quitan la
carga, realizando todas las conversiones por nosotros.
[Section1]
Key1=ghi
Key2=jkl
[Section2]
Key1=mno
Key2=pqr
ErrorHandler:
' ----- Regresar una cadena vacia si hay un error.
On Error Resume Next
If (leerINI IsNot Nothing) Then leerINI.Close(
)
leerINI = Nothing
Return ""
End Function
Caracterstica de
Propsito Equivalente en My.Computer.FileSystem
Visual Basic
ChDir Cambiar el directorio de trabajo La propiedad FileSystem.CurrentDirectory obtiene y
actual en una unidad especfica o establece el directorio de trabajo para que la aplicacin lo
predeterminada. comprenda. Usted establece el directorio activo con una cadena de
ruta absoluta o relativa.
ChDrive Cambiar la unidad de trabajo actual. La propiedad FileSystem.CurrentDirectory no slo
reporta o cambia el directorio activo, tambin modifica la unidad activa.
CurDir Identificar el directorio de trabajo Una vez ms, FileSystem.CurrentDirectory es el
actual y la unidad como una cadena sustituto de esta caracterstica del directorio de Visual Basic.
de ruta completa. CurDir tiene un poco ms de flexibilidad: le permite determinar
el directorio actual en una unidad distinta de la actual. Este puede
hacerse con FileSystem.CurrentDirectory.
Dir Recuperar archivos y directorios en un Los mtodos FileSystem.GetDirectories y
directorio primario que coincide con FileSystem.GetFiles son compatibles con patrones de
un patrn de nombre especfico. comodines cuando se recuperan nombres de directorio y archivo
coincidentes. Dir requiere que lo llame una vez para cada entrada
que se devuelve, y no funciona bien cuando se procesan direcciones
anidadas. Los equivalentes de FileSystem devuelven coleccio-
nes de elementos coincidentes, y pueden descender opcionalmente
por todo el rbol de subdirectorios de una ruta base.
FileCopy Hacer una copia de un archivo. FileSystem.CopyFile proporciona algunas caractersticas
amigables con el usuario ms all de FileCopy. Pero qu pasa
con lo inverso de File y Copy?
FileDateTime Recuperar la fecha y hora de creacin Se usa el mtodo FileSystem.GetFileInfo para recu-
o modificacin de un archivo. perar el objeto FileInfo repleto de detalles acerca de un archivo.
Probablemente se concentrar en la propiedad FileInfo.
LastWriteTime, pero tambin puede obtener la hora de crea-
cin del original y la del ltimo acceso, caractersticas no disponibles a
travs de la funcin inferior y ahora en desdicha FileDateTime.
FileLen Recuperar la longitud de un archivo, Se obtiene un objeto FileInfo mediante el mtodo
en bytes. FileSystem.GetFileInfo, y se accede a la propiedad
Length de ese objeto para obtener el tamao del archivo en bytes.
GetAttr Recuperar los atributos de un archivo Se obtienen detalles de un archivo a travs del mtodo FileSystem.
como un campo de bits. GetFileInfo, y se usa la propiedad Attributes del
objeto FileInfo para examinar su atributo de eleccin. Este
objeto tambin expone un valor IsReadOnl y booleano.
Kill Eliminar un archivo de un directorio Los mtodos FileSystem.DeleteFile y FileSystem.
vaco. DeleteDirectory reemplazan el procedimiento Kill y
proporcionan opciones adicionales no disponibles con Kill.
Adems, no tendr a la polica tocando su puerta preguntando por
qu escribe constantemente Matar, Matar, Matar (Kill).
Caracterstica de
Propsito Equivalente en My.Computer.FileSystem
Visual Basic
MkDir Crear un nuevo directorio. El mtodo FileSystem.CreateDirectory es un reempla-
zo gentil de MkDir. De cualquier manera, mkdir es un antiguo
comando Unix, y usted no est programando en Unix, o s?
Rename Cambiar el nombre de un archivo o Rename es reemplazado por mtodos FileSystem.
directorio. RenameFile y FileSystem.
RenameDirectory distintivos.
RmDir Eliminar un directorio, aunque FileSystem.DeleteDirectory elimina directorio que
contenga archivos. an contienen otros archivos, una accin que rechazaba RmDir.Tam-
bin hay una opcin para enviar los archivos a la Papelera de reciclaje.
SetAttr Modificar los atributos de un archivo Mismo proceso indicado antes para GetAttr. Las propiedades
empleando un campo de bits. Attributes and IsReadOnly del objeto FileInfo son
valores de lectura/escritura, suponiendo que tiene los derechos de
seguridad necesarios para cambiar los atributos.
Por qu Microsoft introducira tantas nuevas caractersticas My que duplican caractersticas exis-
tentes de Visual Basic? Tal vez es una manera de traer consistencia a las prcticas de programa-
cin basadas en archivos mediante un mtodo ms orientado a objetos. O tal vez es slo otra
movida de Microsoft, el gobierno de Estados Unidos, los Caballeros Templarios, Burger King y
otros grupos que pretenden la dominacin mundial al controlarlo a usted, su familia y su comu-
nidad mediante la "mano oculta de instrucciones de cdigo fuente extra largas.
es idntica a:
Dim flujoEntrada As New IO.StreamReader(rutaNombreArchivo)
Para m, la segunda versin es mejor debido a su tersa naturaleza, pero queda entre usted y su
equipo de revisin de cdigo fuente la decisin de cul usar.
Si quiere cargar todo el contenido de un archivo en una matriz String o Byte, no es necesario
abrir un flujo ahora que My incluye los mtodos My.Computer.FileSystem.ReadAllText y el
relacionado ReadAllBytes. Esta instruccin vuelca todo el contenido de un archivo en String:
Dim archivoCompleto As String = _
My.Computer.FileSystem.ReadAllText( _
rutaNombreArchivo)
' ----- Abrir el archivo con los campos delimitados por tabuladores.
archivoOrigen = My.Computer.FileSystem.OpenTextFieldParser( _
archivoOrigenPath, vbTab)
Resumen
La administracin y manipulacin de archivos no es ciruga cerebral. Pero con el sistema de
archivos como eje principal de cualquier sistema operativo, las herramientas y los mtodos para
leer y actualizar archivos parecen multiplicarse como conejos. El .NET Framework usa Stream
como su principal mtodo de interaccin con archivos, de modo que esto debe ayudarle a sim-
plificar las cosas. Por supuesto, apila docenas de clases de envoltura sobre el flujo bsico, pero
se es otro tema.
Resumen | 427
Proyecto
Tengo algunas noticias buenas y otras malas. Las malas noticias son que el Proyecto Biblioteca
no lee ni escribe en archivos estndar, y no tiene necesidad de flujos de archivo. Eso significa que
no agregaremos cdigo al proyecto de este captulo. Las buenas noticias son que an tenemos
algunas cosas interesantes de las cuales hablar. Adems, me imagino que como hemos terminado
ms de la mitad del libro, puede tomarse un descanso.
ACCESO AL PROYECTO
Este captulo no incluye plantillas de proyecto, as no se preocupe en buscarlas en Visual
Studio.
Pero, quin est escuchando? Si usted est ejecutando el programa dentro de Visual Studio,
Visual Basic siempre configura un escucha de registro que despliega el texto en el panel de la
Ventana Inmediato. Pero eso no es muy bueno en una aplicacin compilada e implementada.
Puede disear sus propios escuchas de registro, pero .NET tambin incluye varios escuchas pre-
definidos, todos los cuales pueden habilitarse y configurarse mediante el archivo app.config de la
aplicacin. Si accede a la versin Final del proyecto del captulo 14, encontrar contenido en
su archivo app.config que configura uno de esos escuchas. He aqu una parte de ese archivo, que
le muestra slo las secciones relevantes:
<switches>
<add name="DefaultSwitch" value="Information" />
</switches>
<sharedListeners>
<add name="FileLog" type=
"Microsoft.VisualBasic.Logging.FileLogTraceListener,
Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a,
processorArchitecture=MSIL"
initializeData="FileLogWriter"/>
</sharedListeners>
</system.diagnostics>
La parte nombreusuario es reemplazada por el nombre del usuario que ha iniciado sesin. Las
partes Compaia, Producto y Version representan el nombre de la compaa, el nombre del
producto y el nmero de la versin de su ensamblado, como est definido en los asistentes de su
ensamblado. NombreApl es el nombre de su aplicacin con la extensin .exe eliminada. En mi
sistema Windows Vista, el archivo de registro para el Proyecto Biblioteca aparece aqu:
C:\Users\nombreusuario\Application Data\
ACME\Biblioteca\1.0.0.0\Library.log
Si no le gusta esa ubicacin puede cambiar la salida a cualquier otra que elija. Para ello, necesi-
tar modificar la etiqueta <add> en la seccin <sharedListeners>, agregando dos atributos
adicionales a la etiqueta.
Proyecto | 429
<add name="EventLog"
type="System.Diagnostics.EventLogTraceListener,
System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="sample application"/>
<add name="Delimited"
type="System.Diagnostics.DelimitedListTraceListener,
System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="c:\temp\CiertoArchivo.txt"
delimiter=";;;"
traceOutputOptions="DateTime" />
<add name="XmlWriter"
type="System.Diagnostics.XmlWriterTraceListener,
System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
El atributo initializeData en cada entrada contiene los valores enviados a los argumentos del
constructor de clase relevante. Otros atributos (excepto type) modifican las propiedades del mis-
mo nombre en la clase especificada mediante el atributo type. Para todas las opciones disponibles
para usted de cada escucha, revise la entrada de su clase en la documentacin de Visual Studio.
Para habilitar cualquiera de estos escuchas utilice una etiqueta <add> en la seccin <sour
ce>/<listeners>. El siguiente bloque XML permite todos los escuchas definidos en el pro-
yecto de este captulo:
<sources>
<!-- En esta seccion se define la configuracion del registro
para My.Application.Log -->
<source name="DefaultSource" switchName="DefaultSwitch">
<listeners>
<add name="FileLog"/>
<add name="EventLog" />
<add name="Delimited" />
<add name="XmlWriter" />
<add name="Console" />
</listeners>
</source>
</sources>
Proyecto | 431
433
Por supuesto, podra definir ID como System.Object, y apegarse a cualquier cosa que quiere en
ese campo. Pero System.Object se considera de tipo dbil y no hay nada que evite que mezcle
valores ID Integer y String para diferentes instancias en una matriz de objetos de cliente.
Lo que quiere es un sistema que le permite definir las clases de manera genrica, y mantener la
especificacin de los tipos de datos de ID hasta que en realidad cree una instancia de la clase,
o una coleccin completa de instancias de clase relacionados. Con este tipo de sistema podra
definir una versin de propsito general de la clase personalizada.
Class ClienteConAlgunID
Public ID As <DatatypePlaceholder>
Public NombreCompleto As String
End Class
Ms adelante, cuando es hora de crear una instancia, podran indicar al lenguaje cul tipo de
datos usar para el marcador de posicin.
Dim unCliente As ClienteConAlgunID(reemplazando _
<MarcadorTipoDatos> with Integer)
Esto es lo que los genricos le permiten hacer. He aqu la sintaxis real de Visual Basic que define
la clase de cliente no especfica:
Class ClienteConAlgunID(Of T)
Public ID As T
Public NombreCompleto As String
End Class
El marcador de posicin general, T, aparece en una clusula especial Of, slo despus del nombre
de clase. (No tiene que poner nombre al marcado de posicin T, pero se ha vuelto una tradicin
cuando se presenta cdigo de ejemplo usando genricos.) Como tipo de datos, T puede usarse
en cualquier lugar dentro de la definicin de clase donde no quiere definir de antemano el tipo
de datos. La clase, y su miembro ID, est lista ahora para crear una instancia de ella con un tipo
de datos de reemplazo para T. Para crear una nueva instancia pruebe este cdigo:
Dim clienteNumero As ClienteConAlgunID(Of Integer)
Como antes, no se le pide que use los nombres aburridos T1 y T2. Cualquier nombre que elija,
inclyalo como una lista separada por comas despus de la palabra clave Of. Cuando est listo
para crear una instancia, replique la lista delimitada por comas en el mismo orden, pero em-
pleando tipos reales. En esta instruccin, Integer reemplaza a T1 y String reemplaza a T2:
Dim usarInstancia As VariosTipos(Of Integer, String)
agregando la clusula As para que se parezca a otras declaraciones de Visual Basic. Bueno, puede
dejar de imaginar y empezar a actuar: los marcadores de posicin dan soporte a la clusula
Al agregar la clusula As a una clase especfica, impone una restriccin en el tipo genrico, una
limitacin que debe cumplir para usar el tipo. En este caso, la restriccin dice: Puede propor-
cionar cualquier valor de clase para T, siempre y cuando derive de System.Windows.Forms.
Form. Esto significa que puede crear una instancia de FormOnlyClass empleando uno de los
formularios de su aplicacin, pero no clases distintas de Form.
' ----- Esto funciona.
Dim usarForm As FormOnlyClass(Of Form1)
Cuando agregue una restriccin a un parmetro de tipo, tendr impacto en las caractersticas
que puede usar con ese parmetro de tipo. Considere esta clase genrica destinada a trabajar con
formularios, pero no declarada de esa manera:
Class TrabajarConForms(Of T)
Public Sub CambiarLeyenda(ByVal cualForm As T, _
ByVal nuevaLeyenda As String)
' ----- La siguiente linea no se compila.
cualForm.Text = nuevaLeyenda
End Sub
End Class
Debido a que T tiene que ser del tipo Form o algo derivado de Form, Visual Basic sabe que todos
los miembros de la clase Form, incluido Text, estn disponibles para todas las cosas de T. Por
tanto, la asignacin a cualForm.Text funciona.
Adems de clases, tambin puede usar interfaces para restringir sus tipos genricos.
Class LanzarClase(Of T As IDisposable)
Pero espere, hay ms! Vea, le dije que era como comprar navajas en TV. Adems de sus tipos e
interfaces para todo tipo, tambin puede seguir la clusula As en el marcador de posicin gen-
rico con la palabra clave New.
Class AlgunaClase(Of T As New)
La clusula As New le dice al tipo genrico: Acepta cualquier tipo de T, pero slo si ese tipo
incluye un constructor que no requiere argumentos. Es decir, T debe incluir un constructor pre-
determinado. Una vez definido podr crear nuevas instancias de T (cualquier tipo que resulte)
en su tipo genrico.
Class AlgunaClase(Of T As New)
Public Sub AlgunaSub()
Dim algunaVariable As New T
End Sub
End Class
Si su clase genrica incluye parmetros de varios tipos, cada parmetro incluye su propia clase As
con un tipo distintivo o restriccin de interfaz.
Restricciones simultneas
Es agradable que cada una de esas navajas pueda rebanar una sanda, pero qu pasa si quiere
cortar madera con la misma navaja, o usarla para reparar el cableado elctrico? Est buscando
una herramienta multifuncional, como la de cada marcador genrico de posicin. Si necesita
un marcador de posicin para incluir en una restriccin para una clase especfica, una interfaz y
New a la vez, puede hacerlo. Despus de la palabra clave As, incluya las diversas restricciones
entre llaves.
Class AlgunaClase(Of T As {Windows.Forms.Form, _
IDisposable, New})
Ahora, cualquier tipo que proporcione en la clusula Of cuando cree una instancia de esta clase
debe cumplir todas las restricciones, no slo una de ellas. Y he aqu algo nuevo: puede incluir ms
de una restriccin a interfaz a la vez.
Class AlgunaClase(Of T As {ISerializable, IDisposable})
Y an puede incluir una restriccin de clase y la restriccin New, aun con estas mltiples inter-
faces. (No puede incluir ms de una restriccin de clase para un solo marcador de posicin.)
Si su tipo genrico incluye varios parmetros, cada uno de ellos tiene su propio conjunto de
restricciones mltiples.
contenerPrimero = primero
primero = segundo
segundo = contenerPrimero
End Sub
End Class
Los mtodos genricos son tiles cuando necesita tener una variable local del tipo de marcador
de posicin dentro del mtodo (como se hace aqu con contenerPrimero), pero no conoce el
tipo de antemano. El uso de este mtodo RevertirValores revertido funciona como cualquier
otro mtodo, con la clusula Of adicional.
Dim x As Integer = 5
Dim y As Integer = 10
AlgunaClase.RevertirValores(Of Integer)(x, y)
MsgBox(x) ' Despliega 10
Si estar usando el marcador de posicin para uno o ms de los argumentos de mtodo, Visual
Basic inferir el tipo con base en el valor pasado. Si Visual Basic puede adivinar el tipo de esta
manera, ni siquiera necesita la clusula Of cuando llame al mtodo genrico.
AlgunaClase.RevertirValores(x, y)
Visual Basic se imaginar cul versin usar con base en la clusula Of que incluya con la decla-
racin de instancia.
Dim versionSimple As AlgunaClase(Integer)
Dim versionCompleja As AlgunaClase(Integer, String)
Genricos y colecciones
Los genricos realmente brillan en el rea de las colecciones. La versin inicial de .NET tena,
entre los miles de clases posiblemente tiles, un conjunto de clases de coleccin, todas en el
espacio de nombres System.Collections. Cada coleccin le permite insertar todas las instan-
cias diferentes que desee dentro de esa coleccin, y recuperarlas ms adelante. Las colecciones
difieren en la manera en que la incluye y las recupera, pero le permiten incluir cualquier tipo de
objeto en la coleccin.
Una de las clases de coleccin es System.Collections.Stack. Las pilas le permiten almace-
nar objetos como panqus: el primer objeto que agregue a la pila va en la parte inferior, y cada
uno que agregue va en la parte superior del objeto anterior. Cuando est listo para comer un
panqu (quiero decir, eliminar un elemento) lo toma de la parte superior (a este sistema ltimo
en entrar, primero en salir se le suele llamar LIFO, por Last In, First Out). Los mtodos
Push y Pop administran la adicin y eliminacin de objetos.
Tambin hay un mtodo Peek que busca el elemento superior, pero no lo retira de la pila. Lo
que pasa con las pilas (y otras colecciones similares) es que no tiene que poner slo un tipo de
objeto en ella. Puede mezclar todos los que quiera.
Dim pilaNumerica As New Collections.Stack
pilaNumerica.Push(10) 'Integer
pilaNumerica.Push("Estoy hurgando.") 'String
pilaNumerica.Push(Me.Boton1) 'Control
La pila no es de cuidado, porque slo est tratando todo como System.Object. Pero qu
pasara si necesitara asegurar que slo los enteros se pusieran en la pila? Qu pasara si quiera
limitar una pila a un tipo de datos especfico, pero no quiere escribir clases de pilas separadas
para cada tipo posible?
Esto me suena como un trabajo para los genricos. Tambin le son as a Microsoft. De modo
que agregu una gran cantidad de nuevas colecciones genricas al marco conceptual. Aparecen
en el espacio de nombres System.Collections.Generic. Hay unas cuantas clases diferen-
tes en este espacio de nombres, incluidas clases para listas vinculadas, colas, galletas con chips
de chocolate y diccionarios. Y hey, hay una clase llamada Stack(Of T). Eso es lo nico que
necesitamos.
Dim pilaNumerica As New Collections.Generic.Stack(Of Integer)
pilaNumerica.Push(10)
pilaNumerica.Push(20)
pilaNumerica.Push(30)
Aunque no puede saberlo a partir de la lnea de cdigo fuente, los tipos que pueden ser nulos en reali-
dad estn implementados usando genricos. La versin completa de la declaracin numeroONada es:
Dim numeroONada As Nullable(Of Integer)
Visual Basic simplemente mejor un mtodo abreviado para esta sintaxis mediante el sufijo ?
Puede usar cualquier sintaxis para declarar sus instancias como nulas.
Proyecto
Cuando un cliente saca un libro u otro artculo de la biblioteca, la fecha de vencimiento se
calcula automticamente con base en un nmero de das almacenado en el campo de la base de
datos CodigoTipoMedio.DiasPrestado. Pero qu pasa si esa fecha calculada es un da festivo,
y la biblioteca est cerrada? El cliente podra regresar el libro hasta el da siguiente, e incurrira
en una multa. Esta multa, aunque pequea, podra iniciar una reaccin en cadena en la vida del
cliente que lo llevara a la pobreza, la desesperacin y la adiccin a las telenovelas. Por fortuna,
esto puede evitarse al agregar una lista de das festivos al proyecto. Si la fecha de devolucin de
un artculo falla en un da festivo documentado, el programa ajusta la fecha hacia delante, hasta
que encuentra la siguiente fecha no festiva.
ACCESO AL PROYECTO
Cargue el proyecto Cap16 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap16 (Final) cdigo.
End Class
La tabla Festivos de la base de datos incluye dos campos principales usados en el clculo de
das festivos: TipoEntrada y DetalleEntrada. Almacenemos estos miembros de la clase, y
agreguemos una marca que asegure que la entrada es vlida.
Proyecto | 443
Hemos terminado con esa clase. Ahora slo necesitamos un lugar para mantener nuestros regis-
tros de das festivos. El espacio de nombres System.Collections.Generic incluye unas cuan-
tas clases de coleccin diferentes que podemos usar. Como lo nico que realmente necesitamos
hacer con las festividades una vez que estn en la coleccin es revisarlas, buscando coincidencias,
la lista estndar, sin complicaciones, parece mejor. Su nombre de clase es List(Of T), y su
consulta principal, de acuerdo con la documentacin de .NET, es que le permita a los miembros
acceder por ndice. Eso es correcto.
All est! All est! La clusula Of. sta es una coleccin genrica. S! Muy bien, la fiesta
termin; hora de partir.
Localice el mtodo InitializarSistema, an en el archivo General.vb, y agregue el cdigo que
inicializar el cach de das festivos globales.
Eso es para la infraestructura. Agreguemos algunas rutinas que accedan a esta lista genrica.
Necesitamos una rutina que nos indique, True o False, si una fecha determinada (la fecha de
vencimiento planeada de un artculo de la biblioteca) coincide con cualquiera de los das festivos
o no. Agregue la funcin EsFechaFestiva a General.vb.
Proyecto | 445
Como todo lo que son colecciones no genricas se reduce a System.Object, tendramos que
convertir explcitamente cada objeto de la coleccin a ConjuntoFestivos empleando CType o
una funcin de conversin similar. Pero con una coleccin genrica, Visual Basic se ocupa de eso.
An necesitamos incluir en cach los das festivos de la base de datos, de modo que agregue un
mtodo ActualizarFestivos a General.vb que haga esto.
ErrorHandler:
ErrorGeneral("ActualizarFestivos", Err.GetException(
))
On Error Resume Next
If Not (infoBD Is Nothing) Then _
infoBD.Close() : infoBD = Nothing
Return
End Sub
Ya ha visto mucho cdigo como ste, cdigo que carga registros de una tabla de base de datos en
el programa. No desafiar su inteligencia al explicrselo lnea por lnea.
Hay dos lugares donde necesitamos llamar a ActualizarFestivos: cuando inicia el programa,
y despus, cada vez que se hacen cambios a la lista de festividades. No nos preocuparemos acerca
de que otros usuarios cambien la lista; nos concentraremos en las situaciones en que la aplicacin
local la actualiza. En primer lugar, abra el a veces oculto archivo ApplicationEvents.vb, y agregue
este cdigo al manejador de eventos MyApplication_Startup, justo despus de la llamada
existente a CargarConfiguracionesBaseDeDatos().
ActualizarFestivos()
Una sola cosa ms. Abra el archivo FormularioPrincipal.vb y localice el manejador de eventos
AdminVinculosFestividades_LinkClicked. Es el que le permite al usuario editar la lista de
das festivos. Agregue la misma lnea ActualizarFestivos() al final de esta rutina.
Como puede ver en esta rutina, ya agregamos el editor para administrar la lista de festividades,
lo nico que queda por hacer es acceder a la lista de festividades cuando se pidan prestados
artculos. Haremos eso en un captulo posterior.
Proyecto | 447
Hace muchos aos el control remoto de mi televisor se descompuso. Haba recibido este aparato
de segunda mano de un amigo estudiante (eso debe hablar de la calidad del televisor) y ya era un
poco vieja. Pero an poda ver La isla de Gilligan, entonces por qu quejarse? Pero cuando me
puse en contacto con el fabricante para tener un control de reemplazo, me dijeron que costara
75 dlares! El televisor no costaba eso, y estoy seguro que costaba todava menos producir La
isla de Gilligan.
La TV era casi intil sin el control remoto, de modo que sal y compr un control remoto univer-
sal. Estos dispositivos prcticos tienen los cdigos infrarrojos que los fabricantes de televisores
ms comunes incluyen en sus circuitos. Simplemente rastrea todos los cdigos para encontrar
el de su televisor, y en cosa de minutos (y esto demuestra el milagro moderno de la electrnica)
an tiene la funcionalidad que tena con su control original. Perd todo el uso del sistema de
subtitulaje integrado, pero los botones de encendido, canal y volumen parecan funcionar.
A pesar de sus deficiencias, el control remoto universal poda controlar un televisor, una videoca-
setera y un reproductor de DVD, todo a travs de un conjunto comn de botones. Imagine un
control remoto universal para el desarrollo de Visual Basic. Bueno, deje de imaginar y empiece
a revisar su gua de televisin: ahora Visual Basic tiene el respaldo de LINQ, una nueva caracte-
rstica en Visual Basic 2008 que le permite consultar orgenes de datos sin relacin empleando
una sintaxis comn.
Qu es LINQ?
LINQ, abreviatura de consulta integrada de lenguaje (Language INtegrated Query), no es slo
una sino alrededor de un milln de nuevas tecnologas de Visual Basic y .NET que funcionan en
conjunto para facilitarle su vida en la programacin. Bueno, no es tan fcil en todos los casos. Al
igual que con cualquier nueva tecnologa, tiene cosas buenas y malas.
448
Lo malo
LINQ es un sistema abultado para consulta de datos (una vez que ha establecido la conexin
entre las instrucciones de consulta y los datos). Para algunos de los tipos de LINQ, sobre todo
LINQ to Objects, no hay demasiado que conectar, de modo que la consulta es simple. Para
otras variedades de LINQ, sobre todo del tipo de base de datos, debe crear clases intermedias
que unan sus solicitudes de datos. LINQ es una tecnologa genrica que puede interactuar con
cualquier dato una vez que proporcione el pegamento. Y ese pegamento puede ser muy firme,
en ocasiones.
Como ejemplo, considere LINQ to SQL. Esta implementacin de LINQ necesita una clase que
representa las tablas y los registros que consultar mediante LINQ. No es difcil crear esta clase,
y se parecen mucho a las tablas originales de base de datos. Sin embargo, si modifica la estructura
de su tabla, necesitar modificar la clase intermedia para aprovechar los cambios a la tabla. Es
una tarea que de todos modos necesitara hacer, aun sin LINQ, pero es algo que debe tener en
mente cuando considere la manera de que los programadores aprovechan LINQ.
La naturaleza intermedia de LINQ tambin significa que algn procesamiento de datos puede
ser ms lento cuando se compara con la realizacin de la misma tarea sin LINQ. Capas adiciona-
les de datos y cdigo significan trabajo adicional para su equipo. Pero eso ya es vida en el mundo
de .NET Framework, de modo que yo no evitara LINQ debido a ello.
Qu es LINQ? | 449
Tipos annimos
Los tipos annimos son nuevas caractersticas incluidas en Visual Basic para dar soporte a LINQ,
pero puede usarlos tambin en su propio cdigo. Son exactamente lo que indican: tipos sin
nombre. Bueno, eso no es completamente exacto. Los tipos tienen nombres, pero son generados
de manera automtica por el compilador de Visual Basic, y nunca se muestran directamente en
su cdigo fuente.
Considere una clase tpica diseada para contener informacin sobre selecciones de sushi.
Class Sushi
Public NombrePescado As Cadena
Public CostoPorcion As Decimal
End Class
Los tipos annimos toman esta tersa sintaxis y la llevan un paso adelante al dejar fuera por com-
pleto el nombre de la clase.
Dim comidaSabrosa = New With { _
.NombrePescado = "maguro", .CostoPorcion = 3.5@}
La instancia comidaSabrosa es ahora una instancia de una clase con dos miembros, una cadena
llamada NombrePescado y un valor decimal llamado CostoPorcion. Lo nico que no tiene es
un nombre de clase que usted conozca. Pero Visual Basic sabe lo que es.
Slo por diversin compil el ltimo bloque de cdigo y busqu el nombre del tipo generado.
Helo aqu:
VB$AnonymousType_0`2<T0,T1>
Hmm. An pienso que el sushi sabe mejor. Lo que es realmente interesante es que Visual Basic
cre un tipo genrico con dos tipos de marcadores de posicin de parmetros: T0 (tal vez vincu-
lado con el miembro de cadena NombrePescado) y T1 (tal vez el decimal CostoPorcion).
Los tipos annimos son usuarios importantes de la inferencia de tipo. Visual Basic est adivinan-
do el tipo de datos de cada miembro con base en los datos que proporcione con cada nombre. En
las instancias del sushi, el miembro CostoPorcion es de tipo Decimal con base en las literales
decimales proporcionadas con la definicin de instancia.
LINQ to Objects
LINQ le permite consultar datos de muchas fuentes de datos diferentes, y cada interaccin
de LINQ a datos es administrada por un proveedor de LINQ. Present a los proveedores inclui-
dos con Visual Basic 2008 un poco antes; todos tienen el nombre LINQ to algo. Para m, el
ms sencillo de los proveedores es LINQ to Objects, designado para interactuar con conjuntos
de objetos en memoria. LINQ to Objects le permite procesar consultas con base en colec-
ciones de objetos, matrices de Visual Basic y cualquier objeto que d soporte a las interfaces
IEnumerable o IEnumerable(De T) de NET, incluidas sus propias colecciones persona-
lizadas. (Varios objetos dentro del mundo de ADO.NET dan soporte a estas interfaces, pero
estos tipos caen bajo el proveedor LINQ to DataSet, que se analiza ms adelante.)
Cuando ejecute consultas de LINQ to Objects, la salida de la consulta es un nuevo conjunto de
objetos que contiene un subconjunto de los datos de objeto de origen. Esto le permite ejecutar
Antes de que entremos en algunos de los proveedores LINQ ms compleja, descubramos la sin-
taxis en las consultas de LINQ empleando LINQ to Objects. En las siguientes secciones usar
dos pequeas colecciones de libros como mis datos de origen de consulta.. He aqu la definicin
de cada libro que incluye unos cuantos miembros razonables:
Class Libro
Public Titulo As String
Public IDAutor As String
Public Paginas As Integer
End Class
Los autores aparecen en una clase separada. Las instancias Libro y Autor coinciden a travs del
campo comn IDAutor.
Class Autor
Public IDAutor As String
Public NombreCompleto As String
End Class
Para facilitar nuestra comprensin de la salida de cada consulta, pretendamos que he escrito un
mtodo que despliegue los resultados de cualquier consulta en un formulario de tabla. Llamar
a la rutina MostrarResultados.
La clusula From
Toda consulta bsica a LINQ empieza con la palabra clave From.
Dim bolsaDeLibros = From lb En Biblioteca
MostrarResultados(bolsaDeLibros)
' Resultados --> Guerra y paz LT 1424
' Anna Karenina LT 976
' Ben-Hur LW 544
' Peter Pan JB 192
Estas cuatro palabras son la consulta LINQ ms corta que puede escribir. Almacen los resulta-
dos de la consulta en la variable bolsaDeLibros (con su tipo de datos inferido por la consulta),
pero la consulta tambin puede usarse directamente como una expresin.
MostrarResultados(From lb In Biblioteca)
La palabra clave AS de SQL realiza casi la misma funcin que la palabra clave In en LINQ. Sin
embargo, a pesar de mi tensin interna, prevalece la sintaxis In; no puede usar la sintaxis AS en
LINQ porque la palabra clave As en Visual Basic se usa para asignacin de tipos de datos.
Adems de migrar campos de los objetos originales sobre el conjunto de resultados, puede usar
operadores y funciones para modificar los resultados. En el siguiente ejemplo se usa la funcin
StrReverse para modificar el nombre del ttulo antes de compilar los resultados:
Dim backward = From lb In Biblioteca _
Select StrReverse(lb.Titulo)
MostrarResultados(backward)
' Resultados --> zap y arreuG
' anineraK annA
' ruH-neB
' naP reteP
La clusula Distinct
Como opcin predeterminada, la clusula Select devuelve todos los registros desde el origen.
Obtener informacin completa es algo bueno, pero en ocasiones es demasiado bueno, sobre
todo cuando la informacin contiene duplicados. Por ejemplo, esta consulta devuelve slo el ID
de autor de cada libro disponible:
Dim soloID = From lb In Biblioteca _
Select lb.IDAutor
MostrarResultados(soloID)
' Resultados --> LT
' LT
' LW
' JB
Los resultados estn completos, pero LT apareci dos veces. Dependiendo de sus necesidades,
eso podra ser algo malo. Al agregar la clusula Distinct puede deshacerse de las duplicaciones
innecesarias.
Dim soloID = From lb In Biblioteca _
Select lb.IDAutor _
Distinct
MostrarResultados(soloID)
' Resultados --> LT
' LW
' JB
La palabra clave Distinct busca registros completos de duplicados. Un registro slo se excluye
si todos los campos en ese registro coinciden exactamente con todos los campos de otro.
La clusula Where
Mientras que la clusula Select le permite deshacerse de los campos no deseados, la clusula
Where le permite eliminar objetos completos con base en criterios que usted especifique.
Dim grandesLibros = From lb In Biblioteca _
Where lb.Paginas >= 1000
MostrarResultados(grandesLibros)
' Resultados --> Guerra y paz LT 1424
La ltima caracterstica tambin mostr cmo incluir caractersticas que no son de LINQ, como
la funcin InStr, en sus criterios, permitindole que restrinja los resultados con base en los
resultados calculados.
La clusula Order By
No se garantiza que los resultados de LINQ, dependiendo del origen de los datos, aparezcan en
un orden particular. Para generar resultados de consulta en un orden especfico, utilice la clu-
sula Order By. Las palabras clave Order By preceden uno o ms campos de origen o valores
calculados, delimitados por comas y, como opcin, puede incluir la palabra clave Ascending
o Descending para invertir el orden de cada campo. (Ascending es la opcin predeterminada
para cada campo.)
Dim bolsaDeLibros = From lb In Biblioteca _
Select lb.Paginas, lb.Titulo _
Order By Paginas Descending
MostrarResultados(bolsaDeLibros)
' Resultados --> 1424 Guerra y paz
' 976 Anna Karenina
' 544 Ben-Hur
' 192 Peter Pan
Los campos incluidos en la clusula Order By deben estar presentes en la clusula Select; deje
fuera el prefijo de la variable de rango (lb en este caso). Si utiliza una clusula From sin una
Select debe incluir el prefijo de la variable de rango en sus campos Order By.
Unin de orgenes
Si slo fuera a consultar datos de una sola coleccin de datos u origen, tal vez no necesitara algo
como LINQ, en primer lugar. Cuando llega el momento de que combine resultados de tablas
diferentes, LINQ proporciona de nuevo una sintaxis parecida a SQL para unir las tablas. En
realidad, proporciona dos variaciones, haciendo paralelo con las variaciones de sintaxis a las que
dan soporte diferentes vendedores SQL.
Las palabras clave especiales On y Equals ayudan en la sintaxis de unin. Si su unin incluye cla-
ves mltiples puede usar la palabra clave And para especificar los vnculos de claves diferentes.
Dim resultados = From t1 In Tabla1 _
Join t2 In Tabla2 _
On t1.Clave1 Equals t2.Clave1 _
And t1.Clave2 Equals t2.Clave2
La sintaxis de la segunda unin le permite usar la clusula Where para indicar los vnculos del campo.
Dim bolsaDeLibros = From lb In Biblioteca, _
au In Escritores _
Where lb.IDAutor = au.IDAutor _
Select lb.Titulo, au.NombreCompleto _
Order By lb.Titulo
' Mismos resultados que antes
LINQ incluye otra variacin de unin que genera resultados de consulta genricos. En esas con-
sultas, uno de los campos en cada registro resultante ser una coleccin que contiene varios
resultados. Esta sintaxis permite a LINQ devolver una lista de todos los autores, un autor por
fila, donde cada registro de auto incluye un campo libros, posiblemente con varios valores.
Dim librosAutor = From au In Escritores _
Group Join lb In Biblioteca _
On au.IDAutor Equals lb.IDAutor _
Into Publicado = Group _
Select au.NombreCompleto, Publicado _
Order By NombreCompleto
MostrarResultados(librosAutor)
' Resultados --> Barrie, J. M. Peter Pan
' Tolstoi, Leon Guerra y paz
' Anna Karenina
Wallace, Lew Ben-Hur
Esta consulta tiene una sintaxis un poco extraa, pero crea con xito un conjunto de resultados
con dos columnas: NombreCompleto (para el nombre del autor) y Publicado (para la coleccin
de libros publicados por un autor especfico). Para cada registro devuelto, el miembro Publica-
do es una coleccin subordinada que puede procesarse como cualquier otra coleccin.
Las clusulas Skip While y Take While relacionadas le permiten usar una expresin booleana,
en lugar de un nmero para indicar cundo seguir omitiendo o tomando datos.
Skip y Take son tiles para disponer los resultados en pginas, como cuando se muestra slo
una pgina de resultados a la vez de un conjunto ms largo de resultados consultados. Se puede
usar lgica similar a la siguiente para mostrar slo los registros destinados para PaginaActual:
Dim unaPaginaImportante = From lb In Biblioteca _
Select lb.IDAutor, lb.Titulo _
Skip ElementosPorPagina * PaginaActual _
Take ElementosPorPagina
Una sola advertencia acerca de Skip y Take: s hay diferencias cuando las pone en su consulta.
(Explicar la razn tcnica por la que est en la seccin Ejecucin diferida, ms adelante en este
captulo.) Por ejemplo, considere esta consulta basada en los datos de nuestro libro original:
Dim algunosLibros = From lb In Biblioteca _
Order By lb.Titulo _
Take 2
Esta consulta devuelve Anna Karenina seguida por Ben-Hur, como lo esperara. Pero si mueve
la clusula Take a un lugar anterior, puede obtener un resultado diferente.
Dim algunosLibros = From lb In Biblioteca _
Take 2 _
Order By lb.Titulo
Esta vez, la consulta devuelve Anna Karenina seguida por Guerra y paz. En la primera
consulta, el contenido de Biblioteca se orden por Titulo antes de que se tomaran los dos
registros. En la segunda consulta, los dos registros se tomaron primero, antes de que se aplicara
cualquier ordenamiento.
No slo Take y Skip sufren un impacto por este ordenamiento. Todas las clusulas de su con-
sulta se ven afectadas. Es esencial pensar en la lgica de su consulta, porque una clusula mal
colocada puede darle resultados inesperados.
ToList realiza una operacin similar, creando una nueva coleccin Generic.List basada en
los resultados de la consulta. ToDictionary crea una coleccin Generic.Dictionary, pero
debe proporcionar una funcin a ToDictionary que extrae la clave. En la mayor parte de los
casos, bastar una expresin lambda que identifique el campo clave.
Dim autores = From au In Escritores _
Order By au.NombreCompleto
Dim diccAutores = autores.ToDictionary(Function(x) x.IDAutor)
MsgBox(diccAutores("LW").NombreCompleto)
' Resultados --> Wallace, Lew
Consultas agregadas
Las consultas agregadas le permiten sumar informacin de una consulta ms larga en un re-
sultado condensado o nico. En lugar de empezar con la palabra clave From, las consultas agre-
gadas puras empiezan con la palabra clave Aggregate. Cada consulta agregada usa una o ms
funciones agregadas, como la funcin Sum de la siguiente consulta:
Dim librosNum = Aggregate lb In Biblioteca _
Into Sum(lb.Paginas)
MsgBox(librosNum) ' Despliega: 3136
LINQ incluye ochos funciones agregadas estndar, mostradas en la tabla 17-1. Cada funcin
acepta una expresin que indica lo que debe agregarse durante la consulta.
Tabla 17-1. Funciones agregadas estndar.
Funcin Descripcin
All Devuelve un valor booleano que indica si la expresin que le pas es verdadera para todos los registros. La
clusula All(lb.Paginas > 1000) devolvera False porque slo un libro tiene ms de 1000
pginas.
Any Similar a All, pero devuelve True si slo uno de los registros coincide con la expresin de criterios
proporcionada.
Funcin Descripcin
Average Devuelve el promedio de cualquier expresin que se pase.
Count Devuelve una cuenta de registros con resultados de expresin True. Para devolver una cuenta de todos
los registros en una consulta, use Count(True).
LongCount Igual que Count, pero devuelve Long en lugar de un Integer.
Max Devuelve la expresin numrica mxima a partir del conjunto de registros.
Min Devuelve la expresin numrica mnima a partir del conjunto de registros.
Sum Devuelve la suma de las expresiones numricas a partir del conjunto de resultados.
Es la consulta que slo devuelve libros grandes. La misma consulta que emplea mtodos de
extensin tiene este aspecto:
Dim grandesLibros = Biblioteca.Where(Function(lb) lb.Paginas >= 1000)
LINQ to XML
En el captulo 13 introduje las literales XML, contenido XML que est incrustado en su
cdigo fuente de Visual Basic. Cuando trae LINQ al frente, de pronto tiene una manera
de generar documentos XML largos al combinar conjuntos de registros con una plantilla de
literal XML.
El siguiente bloque de cdigo crea un documento XML empleando nuestras colecciones Bi-
blioteca y Escritores, entremezclando LINQ y XML de una manera que en realidad hace
que me duela la cabeza:
Dim libroXML As XDocument = _
<?xml version="1.0"?>
<listalibros>
<%= From lb In Biblioteca _
Join au In Escritores _
On lb.IDAutor Equals au.IDAutor _
Order By lb.Titulo _
Select _
<libro>
<titulo><%= lb.Titulo %></titulo>
<autor><%= au.NombreCompleto %></autor>
<paginas><%= lb.Paginas %></paginas>
</libro> _
%>
</listalibros>
libroXML.Save("libros.xml")
Observa cmo debe poner los caracteres de continuacin de lnea en las partes LINQ del
cdigo, pero no en la parte XML? S, y tambin lo odio. Pero genera XML agradable. Si busca
La clave para entremezclar XML y LINQ es colocar correctamente los marcadores <%= y %>
alrededor del cdigo especfico de LINQ. Si observa con cuidado el ejemplo, ver que hay dos
conjuntos de marcadores, uno dentro de otro.
<%= From ...
<titulo><%= lb.Titulo %></titulo>
... %>
El conjunto externo de marcadores rodea toda la consulta LINQ, mientras que cada conjun-
to interno de marcadores identifica una variable de reemplazo para incluirla en el contenido
XML.
As como es fcil generar XML usando LINQ, es igual de fcil consultar datos de documentos
XML existentes. Recargar el XML que acabamos de guardar nos permite consultar una lista de
ttulos de libros al entremezclar LINQ con propiedades de eje XML.
Dim libroXML As XDocument = _
XDocument.Load("libros.xml")
Dim desdeXML = From bx In libroXML...<libro> _
Select bx.<titulo>.Value
MostrarResultados(desdeXML)
' Resultados --> Anna Karenina
' Ben-Hur
' Peter Pan
' Guerra y paz
LINQ to Entities
Poco despus del lanzamiento de Visual Studio 2008, Microsoft lanz ADO.NET Entity Fra-
mework. Esta interfaz entre su cdigo de programacin y una base de datos le permitir definir
una vista lgica de su sistema. Por ejemplo, puede crear una entidad llamada Order que incluya
sus tablas de cliente, vendedor, encabezado de orden, detalle de orden y productos, todo en una
vista lgica. Los procedimientos almacenados relacionados pueden ser parte del paquete.
El marco conceptual hace toda la magia al crear un conjunto de clases intermedias y contenido
estructurado XML relacionado que administra el vnculo entre las vistas lgicas y fsicas de los
datos. Estas clases pueden usarse entonces en consultas LINQ, y no es necesario que el autor de
las consultas se preocupe de asuntos triviales como conexiones de base de datos y referencias a
claves externas. En realidad, los programadores han estado escribiendo cdigo como ste durante
aos, abstrayendo el modelo de datos fsico en una vista lgica contra la que es ms fcil progra-
mar. Entity Framework simplemente agiliza y facilita la configuracin de este proceso.
El marco conceptual incluye varias herramientas que le ayudan a construir las entidades desde
las estructuras de base de datos de origen. Una herramienta clave es el diseo de modelo de
datos de entidad de ADO.NET (ADO.NET Entity Data Model Designer), una herramienta
visual de arrastrar y colocar que facilita la creacin de entidades como si se tratara de formula-
rios de Visual Basic.
Debido a que ADO.NET Entity Framework sali despus de Visual Studio 2008, no lo estar
demostrando en este libro.
LINQ to DataSet
LINQ es compatible con consultas de registros dentro de tablas de datos de ADO.NET. Los ob-
jetos DataTabla ADO.NET no dan soporte directo a la interfaz IInumerable, y los campos
dentro de estas tablas son, como opcin predeterminada, sin tipo, lo que en realidad enfurece a
LINQ. La nueva funcionalidad LINQ to DataSet supera ambas limitaciones para que funcione
la consulta de conjuntos de datos.
Al principio de este captulo, vimos ejemplos de LINQ que usaban la clase Libro. Mantenga-
mos esos datos de ejemplo, pero pretendamos que los datos aparecen ahora en una instancia
DataTabla de ADO.NET. La tabla tendr cuatro registros (para los cuatro libros de nuestro
ejemplo) y tres columnas: Titulo, IDAutor y Paginas.
LINQ to DataSet usa mtodos especficos del objeto de conjunto de datos que fuerzan a los
objetos de ADO.NET en algo con lo que LINQ puede interactuar y en una manera con fuerte
imposicin de tipo.
Dim opciones = _
From lb In libroTabla.AsEnumerable( ) _
Where lb.Field(Of Integer)("Paginas") >= 1000 _
Or (lb.Field(Of Integer)("Paginas") < 1000 _
And InStr(lb.Field(Of String)("Titulo"), "-") > 0) _
Select New With _
{.Titulo = lb.Field(Of String)("Titulo")}
LINQ to SQL
LINQ to SQL es el proveedor que permite que consultas de LINQ interacten con bases de
datos de SQL Server. Debido a que el proyecto Biblioteca usa SQL Server, dedicaremos un poco
ms de tiempo a esta tecnologa. Al igual que con LINQ to Entities, LINQ to SQL funciona
mediante clases intermedias. Aunque podra proporcionar una vista lgica diferente de sus tablas
Si hace clic en el botn Mostrar todos los archivos en el Explorador de soluciones, puede acceder
al archivo de diseador .dbml, Biblioteca.designer.vb. Este archivo contiene las clases intermedias
generadas usando LINQ to SQL. En cuanto al uso de la tabla Actividad en nuestras consultas
LINQ, he aqu las partes relevantes del cdigo fuente autogenerado:
<System.Datos.Linq.Mapping.DatabaseAttribute(Name:="Biblioteca")> _
Partial Public Class LibraryDataContext
Inherits System.Datos.Linq.DataContext
<Column(Storage:="_NombreCompleto", _
DbType:="VarChar(50) NOT NULL", CanBeNull:=false)> _
Public Property NombreCompleto() As String
Get
Return Me._NombreCompleto
End Get
End Property
End Class
Ejecucin diferida
Cuando construye una consulta de LINQ, Visual Basic no la procesa de inmediato. En cambio,
difiere la ejecucin, ejecutando la consulta slo cuando solicite un registro de los resultados. Esto
le permite generar una consulta en partes, y no tiene que consumir ciclos de CPU hasta que en
realidad necesita los datos finales.
En este cdigo, el ordenamiento de los registros no sucede hasta la segunda instruccin. Pero eso
no importa porque nada se procesa en realidad en la primera instruccin. Recuerde que LINQ
slo est en realidad convirtiendo sus consultas en mtodos de extensin y expresiones lambda.
La asignacin de algunosLibros est haciendo algo como esto:
algunosLibros = Biblioteca.Select("Titulo, Paginas")
es diferente de
Biblioteca.Skip(2).Take(2)
Resumen
Esa fue una revisin general rpida de LINQ con algunas de las permutaciones de su primer lan-
zamiento. Parece mucho, pero slo he cubierto los aspectos bsicos. Adems de consultar datos,
tambin puede actualizar los datos almacenados mediante instrucciones LINQ especialmente
creadas. Y la capacidad de crear su propio proveedor de LINQ significa que los almacenes de
tipos de datos que LINQ puede procesar son ilimitados.
La principal desventaja de LINQ es que, sobre todo para LINQ to SQL, las instrucciones SQL
y el cdigo MSIL que LINQ genera al final de cuentas con base en su consulta tal vez no ser
tan eficiente como el que podra crear por su cuenta. Algunas de sus consultas LINQ pueden
ejecutarse tan lentamente que no tiene otra opcin que reemplazarlas con caractersticas previas
a LINQ. Pero para los propsitos de consulta ms comunes, sobre todo entre orgenes de datos
divergentes, LINQ es un paso gigante hacia delante.
Resumen | 469
ACCESO AL PROYECTO
Cargue el proyecto Cap17 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap17 (Final) cdigo.
El cdigo fuente relacionado tiene alrededor de 1000 lneas, muchas de ellas concentradas en
llenar los dos cuadros de lista y el contenido de detalle de HTML. La bsqueda realizada en el
formulario principal llama a este formulario de bsqueda mediante el mtodo IniciarBusque-
da. La bsqueda real en la base de datos de artculos coincidentes ocurre en el mtodo Reali-
zarBusqueda, que es llamado por IniciarBusqueda. RealizarBusqueda incluye consultas
LINQ que viajan a la base de datos Biblioteca y de regreso mediante el proveedor LINQ to SQL.
Se incluyen consultas para todos los tipos diferentes de bsquedas: ttulo, autor, tema, palabra
clave, editor, serie, cdigo de barras y algunas bsquedas de nmero de ID, principalmente para
uso interno. El tipo de bsqueda realizado determina cul de los tres paneles se despliega (por
medio de la variable tipoResultado). Una bsqueda de autor despliega el PanelCoinciden-
cias con una lista de nombres de autor coincidentes; una bsqueda de ttulo despliega elemen-
tos coincidentes en el panel PanelArticulos.
Antes de que revisemos el cdigo LINQ necesitamos configurar algunas cosas en el resto de la
aplicacin para que d soporte a estas nuevas consultas LINQ. He deshabilitado el archivo Bus-
quedaArticulos.vb de la compilacin por ahora porque slo generara errores al generarse.
Aunque LINQ to SQL es sorprendente, aun requiere el toque humano (es decir, el suyo) para
ayudarle a localizar las tablas de la base de datos de SQL Server. Usaremos el diseo relacional de
objetos con el que jugamos antes en este captulo. Seleccione el comando Proyecto Agregar
nuevo elemento del men de Visual Studio. En el cuadro de dilogo Agregar nuevo elemen-
to, seleccione Datos de la lista Categoras, seleccione Clases de LINQ to SQL del campo Plan-
tillas y escriba Biblioteca.dbmlen el campo Nombre antes de hacer clic en el botn Agregar.
Aparece una ventana de diseador O/R.
Proyecto | 471
De regreso al cdigo del proyecto del captulo 12 agregamos un mtodo de extensin a la clase Sql-
Client.SqlDataReader que forma un nombre de autor a partir de una consulta de base de datos.
<System.Runtime.CompilerServices.Extension(
)> _
Public Function FormarNombreAutor ( _
ByRef infoBD As SqlClient.SqlDataReader) As String
Proyecto | 473
<System.Runtime.CompilerServices.Extension(
)> _
Public Function FormarNombreAutor( _
ByVal autor As QAutor) As String
' ----- Dado el registro de un autor, regresar el nombre formado.
Dim nombreAutor As String
Si compara este cdigo fuente con la versin SqlDataReader encontrar que esta versin es
mucho ms limpia, porque hace referencia a miembros de clase en lugar de campos de base de
datos mediante un lector. Gracias LINQ!
Esto es todo en cuanto a los cambios en el soporte de LINQ. Habilite el archivo BusquedaArti-
culos.vb al seleccionarlo en el panel Explorador de soluciones y cambiando su propiedad Accin
de compilacin de Ninguna a Compilacin. Ahora regresemos al cdigo en ese archivo.
La rutina RealizarBusqueda consta principalmente de una gigantesca instruccin If, con di-
ferentes condiciones para la mayor parte de los tipos diferentes de bsqueda. La ltima clusula
Else maneja todas las bsquedas que se rellenarn en la lista del panel PanelArticulos del
formulario. sa es la lista que muestra los artculos reales. Tambin contiene una gran cantidad
de instrucciones If. Pero lo realmente estupendo es su consulta LINQ consulta. En lugar de slo
escribir una consulta simple, es una consulta compleja que se construye poco a poco. La consulta
empieza con los fundamentes, solicitando registros coincidentes de la tabla ArticuloConNombre
El tipo de bsqueda tambin ajusta la consulta. Por ejemplo, una bsqueda por palabra clave
agrega palabra claves especificadas por el usuario como criterio.
conjuntoClaves = New Generic.List(Of String)
conjuntoClaves.AddRange(Split(buscarTexto.ToUpper, ","))
consultaArticulo = From ni In consultaArticulo _
Let conjuntoClave = (Aggregate ik In ni.QClaveArticulo _
Into Any(conjuntoClaves.Contains( _
ik.QClave.NombreCompleto.ToUpper))) _
Where conjuntoClave = True _
Select ni
Esa adicin us una subconsulta Aggregate dentro de la consulta principal. La palabra clave
Let, parte de LINQ, asigna una subconsulta u otro tipo de resultado a una variable temporal
dentro de la consulta (conjuntoClave en este caso) de modo que puede hacerse referencia des-
de cualquier lugar de la consulta.
Una vez que se han agregado las clusulas Where se ordena y usa toda la consulta.
consultaArticulo = From ni In consultaArticulo _
Order By ni.Titulo, ni.Subtitulo
Algunas de las consultas LINQ de la rutina RealizarBusqueda son muy sencillas. He aqu el
cdigo que hace una bsqueda del nombre del editor:
' ----- Preparar la consulta para una busqueda de editor.
contenerTexto = Trim(buscarTexto)
If (InStr(contenerTexto, "*") = 0) Then contenerTexto &= "*"
Dim consultaEditor = From pb In bibliotecaDC.QEditor _
Where pb.NombreCompleto Like contenerTexto _
Order By pb.NombreCompleto
No parece muy diferente de lo que esperara de una consulta SQL. Algo agradable es que los
comodines usan el carcter * en lugar del carcter % estndar de SQL.
Despus de procesar esta consulta, los resultados LINQ se rastrean y los registros se mueven a la
lista CoincidenciaGeneral.
For Each articuloPublicado In consultaEditor
CoincidenciaGeneral.Items.Add(New DatosListaElementos ( _
articuloPublicado.NombreCompleto, CInt(articuloPublicado.ID)))
Proyecto | 475
Esto es slo ms del mismo cdigo que ha visto en captulos anteriores. Carga el control List-
Box con objetos DatosListaElementos, cada uno con un nombre de despliegue y un nmero
de ID de la base de datos. Eso es adecuado para una lista con requisitos de despliegue simples.
Pero si revisa la figura 17-4, queda claro que queremos algo un poco ms interesante para la lista
de artculos coincidentes. Queremos columnas, y las columnas requieren datos razonables.
Para almacenar estos datos haremos una nueva clase, llamada DatosArticulosCoincidentes,
que funciona como DatosListaElementos, pero con ms campos de datos.
Private Class DatosArticulosCoincidentes
Public IDArticulo As Integer ' ArticuloConNombre.ID
Public Titulo As String
Public Subtitulo As String
Public Autor As String
Public TipoMedio As String
Public NumeroLlamada As String
Como esta clase se usar slo para desplegar artculos coincidentes en este formulario, la he he-
cho subordinada dentro de la clase del formulario ms grande BusquedaArticulos. El mtodo
ToString da salida al texto que aparece en la lista. No generaremos la salida en columna real
hasta el siguiente captulo. Por ahora slo desplegaremos el ttulo y autor.
Los paneles PanelCoincidencias y PanelArticulos incluyen un botn Buscar que inicia
una nueva llamada a RealizarBusqueda con base en el artculo seleccionado en la lista. El
botn Buscar del panel PanelArticulos recupera el objeto DatosArticulosCoincidentes
seleccionado de la lista y realiza la nueva bsqueda.
Private Sub AccBuscarArticulo_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles AccBuscarArticulo.Click
' ----- Buscar el articulo con el ID seleccionado.
Dim idArticulo As Integer
Proyecto | 477
A medida que el cliente visita cada panel, las llamadas al mtodo AgregarHistoriaBusqueda
llenan la pila con cada artculo nuevo visitado.
Private Sub AgregarHistoriaBusqueda( _
ByVal tipoBusqueda As Biblioteca.MetodosBusqueda, _
ByVal buscarTexto As String)
' ----- Agregar un articulo a la historia de busqueda.
Dim nuevaHistoria As HistoriaBusquedaArticulos
Dim desplegartexto As String
Ms adelante, cuando el cliente haga clic en uno de los botones Atrs, el manejador de eventos
ElementosMenuAtras_Click examina la pila de historia y llama a RealizarBusqueda, se-
gn sea necesario. Y como almacenamos los objetos de HistoriaBusquedaArticulos en una
pila genrica, no tenemos que convertirlos especficamente de System.Object; el programa
slo sabe qu tipo de datos son.
El contenido proporcionado por esta rutina es HTML estndar, pero con algunos vnculos
especialmente creados que dejan que el programa de biblioteca realiza bsquedas adicionales
en los detalles del elemento de biblioteca desplegado.
La mayor parte del HTML es un patrn, y parece una vergenza desperdiciar clulas cere-
brales haciendo unin de cadenas slo para incluirlo. En cambio, almacen gran parte del
HTML como un recurso de archivo de texto a travs del panel Recursos de las propiedades
del proyecto. En ese panel, hice clic en el botn Agregar recurso, hice clic en el elemento de
men Agregar nuevo archivo de texto e ingrese CuerpoBusquedaArticulo como nombre del
nuevo archivo de texto (vase la figura 17-6).
Proyecto | 479
Si est familiarizado con HTML, reconocer la mayor parte del contenido como una hoja de
estilos en cascada (CSS, Cascading Style Sheet) incrustada. Sus diversas reglas de formato traern
un aspecto especfico y consistente al contenido de explorador que aparece dentro del formulario
de bsqueda de artculos. Esto no es un libro sobre CSS, pero hay algunos buenos libros en su
librera local que puede llmar a travs de las reglas y sintaxis si est interesado.
Puede encontrar la parte del contenido HTML en el Explorador de soluciones, dentro de la
rama Recursos. Tal vez ya observ que las etiquetas de cierre </body> y </html> no estn in-
cluidas. Adjuntaremos eso en el mtodo GenerarHTMLYVinculos. Debido a que la unin de
cadenas es notoriamente lenta, decid usar la clase StringBuilder, una clase especial parecida
a una cadena con diseo personalizado para hacerlo ms rpido cuando agrega contenido de
La mayor parte del cdigo agrega texto simple al generador de cadenas cuerpoDetalle
empleando su mtodo AppendLine. He aqu el cdigo que agrega el ttulo principal del libro:
textoSql = "SELECT Titulo, Subtitulo FROM ArticuloConNombre " & _
"WHERE ID = " & idArticulo
infoBD = CrearLector(textoSql)
infoBD.Read()
cuerpoDetalle.AppendLine("<h1>" & _
CodigoHTML(CStr(infoBD!Titulo)) & "</h1>")
Proyecto | 481
La propiedad e.Url.Scheme devuelve la parte del URL antes de los caracteres ://, mientras
e.Url.Host devuelve el primer componente delimitado por diagonales justo despus de estos
caracteres. Es donde almacenamos el ndice en el diccionario ConjuntoVinculosArticulos.
El mtodo SeguirVinculoArticulo extrae los detalles de bsqueda de ConjuntoVinculos
Articulos y llama al mtodo RealizarBusqueda confiable, que da lugar a una nueva bsque-
da que se almacena en la historia de bsqueda.
Private Sub SeguirVinculoArticulo(ByVal idEntrada As Integer)
' ----- Dada la posicion de un caracter en el panel de texto de un
' solo elemento, seguir el vinculo indicado.
Dim buscarVinculo As VinculoArticuloUnico
He aqu la parte del nuevo cdigo que rellena la lista de mtodos de bsqueda:
' ----- Cargar en la lista de tipos de busqueda.
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por titulo", MetodosBusqueda.PorTitulo))
TipoBusqueda.SelectedIndex = 0
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por autor", MetodosBusqueda.PorAutor))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por tema", MetodosBusqueda.PorTema))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por clave (cualquier coincidencia)", _
MetodosBusqueda.PorPalabraClaveCualq))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por clave (todas las coincidencias)", _
MetodosBusqueda.PorPalabraClaveTodas))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por editor", MetodosBusqueda.PorEditor))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por serie Name", MetodosBusqueda.PorSerie))
TipoBusqueda.Items.Add(New DatosListaElementos( _
"Buscar por codigo de barras", MetodosBusqueda.PorCodigoBarras))
El botn Limpiar del panel principal restablece todos los campos y los prepara para una nueva
bsqueda. Agregue un nuevo manejador de eventos AccLimpiarBusqueda_Click usando el
mtodo de seleccin de campos arriba de la ventana del editor de campo o haciendo doble clic
en el botn Limpiar en el propio formulario. Luego agregue el siguiente cdigo al manejador.
Proyecto | 483
Debido a que la aplicacin Biblioteca tal vez ser usada por muchos clientes distintos en todo
el da, debemos suponer que una persona diferente est usando el programa cada vez que el for-
mulario devuelve el panel de bsqueda. Simulemos un clic en el botn Limpiar cada vez que el
usuario ve el panel de bsqueda. Localice el mtodo TareaArtBiblioteca y agregue el siguien-
te cdigo al final de la rutina, justo antes de la instruccin TextoBusqueda.Focus( ).
AccLimpiarBusqueda.PerformClick()
If (ActSearchLimits.Top = LabelMoreLimitsTop.Top) Then _
ActSearchLimits.PerformClick()
Con la intencin de ser lo ms amigable posible con el usuario, agreguemos algn texto de ayu-
da al panel de bsqueda, que vare dependiendo del tipo de bsqueda seleccionado en la lista
desplegable Tipo de bsqueda. Agregue un nuevo manejador de eventos TipoBusqueda_Se-
lectedIndexChanged y luego agregue su cdigo.
No lo incluir todo aqu porque es ms bien repetitivo. El cdigo simplemente examina la se-
leccin actual en el control TipoBusqueda, y establecer la etiqueta EtqDatosConsejosBqd en
algn texto de ayuda descriptivo.
Estamos llegando al final. Lo nico que queda es realizar la bsqueda cuando el usuario hace clic
en el botn Buscar. Agregue un manejador de eventos para AccBuscar_Click y luego agregue
su cdigo.
La mayor parte de esta rutina revisa entrada vlida antes de llamar al formulario BusquedaAr-
ticulos mediante su mtodo pblico IniciarBusqueda.
Call (New BusquedaArticulos).IniciarBusqueda( _
CType(searchMethod, Biblioteca.MetodosBusqueda), _
Trim(TextoBusqueda.Text), limiteMedio, limiteUbicacion)
Proyecto | 485
Una imagen vale ms que mil palabras (o varios miles de lneas de cdigo fuente, si est generan-
do una imagen de mapa de bits con l). Escribir cdigo para manipular imgenes con varios ni-
veles de color, o para trazar arte vectorial de varias capas, puede ser una pesadilla de contorsiones
geomtricas y lgebra lineal. Lo hacen a uno echar de menos los das de las computadoras previas
a la pantalla. La primera clase de programacin que tom usaba una DECWriter, una terminal
basada en impresora que no tena pantalla, e inclua las capacidades grficas de una medusa.
Era perfecta para m. No poda dibujar una lnea recta, de todos modos, y no necesitaba alguna
bonita terminal de pantalla de video que me lo recordara.
Las imgenes incluidas en los primeros sistemas de pantalla no eran mucho mejores. Terminales
tontas, como la popular VT100, inclua algunas imgenes de caracteres simples que desplegaban
lneas y bloques bsicos. Cada parte grfica era exactamente del tamao de un carcter y cualquier
imagen que quisiera desplegar tena que caber en una cuadrcula incmoda de 80 24.
Por fortuna para los aficionados al arte de todas partes, las computadoras han recorrido mucho
camino en el departamento grfico. GDI+, el sistema de dibujo estndar de .NET, incluye ca-
ractersticas de dibujo complejas que haran llorar a una DECWriter. Construida sobre la vieja
tecnologa de la interfaz de dispositivo grfico (GDI, Graphics Device Interface) de Windows,
GDI+ incluye comandos para dibujar lneas, texto e imgenes en el mundo mejorado de Picasso
de las imgenes 2D.
Ms all de GDI+, .NET tambin proporciona soporte para la nueva base de presentacin
de Windows (WPF, Windows Presentation Foundation), una interfaz de usuario y un sistema
de presentaciones multimedia muy ricos basados en parte en XML. WPF incluye caractersti-
cas de despliegue e interaccin que van ms all de GDI+, aunque hay unas cuantas caracte-
rsticas en GDI+ que estn ausentes en WPF. Aunque har una breve revisin de WPF en este
captulo, la mayor parte de l (y todo el cdigo de la interfaz de usuario del proyecto Biblioteca)
se concentrar en GDI+.
486
GDI GDI+
Figura 18-1. La maravilla que es GDI+.
Seleccin de un lienzo
La mayor parte del dibujo en .NET ocurre en el contexto de un objeto Graphics. (Para quienes
estn familiarizados con el desarrollo previo a .NET en Windows, esto es similar a un contexto de
dispositivo.) Los objetos Graphics proporcionan un lienzo en que usted dibuja lneas, formas,
imgenes de mapa de bits y macros de dibujo grabadas previamente. El objetoGraphics no
Algunos eventos, sobre todo Paint para formularios y controles, proporciona acceso a un objeto
Graphics mediante los argumentos del evento.
Private Sub PictureBox1_Paint(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles PictureBox1.Paint
Dim pintarLienzo As Graphics = e.Graphics
End Sub
Tambin puede crear un objeto Graphics que no est relacionado con cualquier rea de desplie-
gue existente al asociarla con un mapa de bits.
Dim verdaderoMapaBits As New Bitmap(50, 50)
Dim lienzo = Graphics.FromImage(verdaderoMapaBits)
Recuerde que todos los cambios hechos a la instancia lienzo tendrn impacto en la imagen
verdaderoMapaBits.
Si crea un objeto Graphics dentro de un evento, en realidad necesita desecharlo antes de salir
del manejador de eventos. No hay garanta de que el objeto Graphics an ser vlido en un
evento posterior. Adems, es fcil volver a crear otro objeto Graphics en cualquier momento.
Plumas
Las plumas son herramientas de dibujo de lneas usadas con los comandos de dibujo de un ob-
jeto Graphics. Una pluma bsica tiene un color y un relleno slidos.
' ----- Una pluma roja de cinco unidades de ancho.
Dim plumaRoja As New Pen(Color.Red, 5)
Al igual que con los objetos Graphics, cualquier Pen puede crearse usando la palabra clave New
y debe desecharse de manera apropiada cuando haya terminado con l.
plumaRoja.Dispose()
' ----- Dibujar una linea basica de 1 pixel usando el color de la barra de titulo.
usarPluma = New Pen(SystemColors.ActiveCaption, 1)
e.Graphics.DrawLine(usarPluma, 10, 10, 200, 10)
usarPluma.Dispose( )
' ----- Dibujar una linea de guiones mas gruesa con extremos de flecha
' y bola. Cada segmento de guion tiene un extremo en triangulo.
usarPluma = New Pen(Color.FromName("Red"), 5)
usarPluma.DashCap = Drawing2D.DashCap.Triangle
usarPluma.StartCap = Drawing2D.LineCap.ArrowAnchor
El cdigo muestra que hay unas cuantas maneras diferentes de especificar un color, ya sea por su
nombre predefinido (Color.White y SystemColors.ActiveCaption), un nombre de cadena
(usando Color.FromName) o su valor en alfa-rojo-verde-azul (Color.FromArgb). La ltima
versin le permite proporcionar diferentes valores para los componentes de la mezcla alfa (que
establece el nivel de transparencia, de 0 para completamente diferente a 255 para completamen-
te opaco) y el rojo, verde y azul de lo que se denomina a todo color.
Casi todas las propiedades especficas de pluma que demostr aqu se explican por s solas, de
alguna manera. Al igual que con casi todo en GDI+, la abrumadora cantidad de caractersticas
disponibles imposibilitan documentarlas por completo en un captulo pequeo, mucho menos
proporcionar una buena noche de sueo para los autores que disean estos captulo. Simple-
mente pedir al lector que revise la documentacin en lnea para la clase Pen para obtener todos
los detalles.
Brochas
Las brochas se usan para rellenar espacios entre lneas dibujadas, aunque haga esas lneas com-
pletamente invisibles. GDI+ incluye varios tipos de brochas, incluidas brochas slidas (de un solo
color bsico), brochas de patrn (que son agradables pero generales), brochas de textura (donde
se utiliza un mapa de bits personalizado) y brochas de degradado (que degradan poco a poco un
color en otro a travs de la brocha). La clase System.Drawing.Brushes incluye algunas bro-
chas slidas predefinidas con base en el nombre de un color. Al igual que con las plumas debe
deshacerse de las brochas que cree, pero no de las brochas slidas definidas por el sistema.
e.Graphics.Clear(Color.White)
' ----- Usar una imagen para la brocha. Estoy usando la imagen
' "BuscarArticulo.bmp" usada en el proyecto Biblioteca.
' y que se encuentra en la carpeta Imagenes del codigo
' de este libro.
usarBrocha = New TextureBrush(Image.FromFile( _
"BuscarArticulo.bmp"))
e.Graphics.FillRectangle(usarBrocha, 200, 70, 150, 50)
usarBrocha.Dispose( )
End Sub
Si la fuente que necesita no est disponible y no est seguro de cul usar, deje que GDI+ elija por
usted. Incluya unas cuantas fuentes genricas para caso de emergencia.
Drawing.FontFamily.GenericMonospace
Drawing.FontFamily.GenericSansSerif
Drawing.FontFamily.GenericSerif
En la figura 18-4 se muestra la salida de este bloque de cdigo. En casi todo el cdigo de ejemplo
de este captulo, dar salida al contenido de un control PictureBox al que he llamado Pictu
reBox1, que he colocado en el formulario de una nueva aplicacin de Windows Forms. Tam-
bin he establecido la propiedad BorderStyle en FixedSingle y su propiedad BackColor
en White, de modo que pueda visualizar las orillas del lienzo. El dibujo ocurre en el manejador
de eventos Paint, al que se llama cada vez que el cuadro de imagen necesita actualizarse, como
cuando otra ventana la oculta y luego desaparece. En los ejemplos de cdigo restantes, no inclui-
r la definicin del mtodo Sub PictureBox1_Paint, slo el cdigo que va en el interior.
Por supuesto, puede mezclar y buscar coincidencias en fuentes en un solo lienzo de salida. Este
cdigo incluye texto usando Arial 14 y Arial 18:
Dim fuenteBasica As New Font("Arial", 14)
Dim fuenteDestacada As New Font("Arial", 18, FontStyle.Bold)
Dim desplazamiento As Single = 0.0
Dim mostrarTexto As String
Dim tamanoTexto As Drawing.SizeF
mostrarTexto = "texto"
tamanoTexto = e.Graphics.MeasureString(mostrarTexto, fuenteBasica)
e.Graphics.DrawString(mostrarTexto, fuenteBasica, _
Brushes.Black, desplazamiento, 0)
desplazamiento += tamanoTexto.Width
mostrarTexto = "destacado."
fuenteDestacada.Dispose( )
fuenteBasica.Dispose( )
La salida de este cdigo aparece en el cuadro superior de la figura 18-5, y es correcto. Pero quiere que
las orillas inferiores de las partes del cuerpo principal de cada bloque de texto (es decir, la lnea base
de cada bloque) se alinee apropiadamente, como se muestra en el cuadro inferior de la figura 18.5.
Hacer esto de la bonita alineacin de las cosas es como un dolor en el cuello. Tiene que hacer
todo tipo de mediciones con base en el diseo de la fuente original, como se extrapola en el
dispositivo en pantalla basada en pixeles. Luego conecte el hueso de la rodilla con el del muslo,
etc. He aqu el cdigo que us para generar la segunda imagen alineada.
Dim fuenteBasica As New Font("Arial", 14)
Dim fuenteDestacada As New Font("Arial", 18, FontStyle.Bold)
Dim desplazamiento As Single = 0.0
Dim mostrarTexto As String
Dim tamanoTexto As Drawing.SizeF
Dim arribaBasico As Single
Dim arribaDestacado As Single
Dim factorDestacado As Single
Dim factorBasico As Single
' ----- Dibujar una linea que pruebe la alineacion del texto.
e.Graphics.DrawLine(Pens.Red, 0, arribaDestacado, _
e.ClipRectangle.Width, arribaDestacado)
mostrarTexto = "texto"
tamanoTexto = e.Graphics.MeasureString(mostrarTexto, fuenteBasica)
e.Graphics.DrawString(mostrarTexto, fuenteBasica, _
Brushes.Black, desplazamiento, arribaDestacado - arribaBasico)
desplazamiento += tamanoTexto.Width
mostrarTexto = "destacado."
tamanoTexto = e.Graphics.MeasureString(mostrarTexto, fuenteDestacada)
e.Graphics.DrawString(mostrarTexto, fuenteDestacada, _
Brushes.Black, desplazamiento, 0)
desplazamiento += tamanoTexto.Width
fuenteDestacada.Dispose()
fuenteBasica.Dispose()
Hay muchos clculos ms en ese cdigo. Y ni siquiera tratar de abarcar cosas como el interletra-
je, las ligaduras o cualquier otra cosa que tenga que ver con la tipografa. De cualquier manera,
si necesita hacer manipulacin compleja de fuentes, GDI+ expone todos los detalles para que
pueda hacerlo de manera apropiada. Si slo quiere dar salida lnea tras lnea usando la misma
fuente, llame al mtodo GetHeight de la fuente para cada lnea que se despliegue:
desplazamientoVertical += useFont.GetHeight(e.Graphics)
Basta de cosas complejas. Tambin hay cosas fciles y atractivas que hacer con el texto. Observ
que la salida de texto usa brochas y no plumas? Esto significa que puede dibujar texto usando cual-
quier brocha que cree. Este bloque de cdigo usa la brocha con la imagen de mapa de bits Buscar
Articulo.bmp del proyecto Biblioteca para desplegar algn texto basado en mapa de bits.
Dim usarBrocha As Brush = New TextureBrush( _
Image.FromFile("BuscarArticulo.bmp"))
Dim usarFuente As New Font("Arial", 60, FontStyle.Bold)
e.Graphics.DrawString("Guau.", usarFuente, usarBrocha, 0, 0)
usarFuente.Dispose( )
usarBrocha.Dispose( )
Creacin de imgenes
Tal vez ms que cualquier cosa, Internet ha echado combustible a la necesidad de estmulo visual
del usuario promedio de computadora. Los sitios Web estn llenos de GIF, JPG, TIFF y una va-
riedad de otros formatos de imagen. Aunque trate con aplicaciones que no sean Web, es proba-
ble que como programador, entrar en contacto ms frecuente con imgenes. Por fortuna, GDI+
incluye caractersticas que le permiten administrar y manipular esas imgenes con facilidad.
El formato de archivo BMP es el mapa de bits nativo incluido en Microsoft Windows, pero no
es tan comn en el mundo Web. Sin embargo, nada de esto le importa a GDI+. Puede cargar y
administrar archivos usando los siguientes formatos grficos:
Archivos de mapas de bits BMP de Windows de cualquier nmero de colores y tamao.
Archivos del formato de intercambio de imgenes (GIF, Graphics Interchange Format) de
CompuServe, usados por lo general para imgenes que no son fotografas en Internet.
Archivos del grupo comn de expertos en fotografa (JPEG, Joint Photographic Experts
Group), de uso comn en fotografas y otras imgenes en Internet. Los archivos JPEG estn
comprimidos internamente para reducir el tamao del archivo, pero con la posible prdida
de calidad en la imagen.
Archivos de imagen intercambiable (EXIF, Exchangeable Image File), una variacin de
JPEG que almacena fotografas profesionales.
Archivos de imagen porttil de red (PNG, Portable Network Graphics), que son similares a
archivos GIF, pero con algunas caractersticas mejoradas.
Archivos de formato de archivo de imagen con etiqueta (TIFF, Tag Image File Format), que
son una especie de combinacin de todos los dems formatos de archivo. Algunas organiza-
ciones gubernamentales almacenan imgenes digitalizadas utilizando TIFF.
Metaarchivos, que almacenan arte de lnea vectorial en lugar de imgenes de mapa de bits.
Archivos de cono (ICO), que se usan para conos estndar de Microsoft Windows. Puede
cargarlos como mapa de bits, pero tambin hay una clase Icon distintiva que le permite
tratarlos en maneras ms parecidas a conos.
Se usan tres clases primarias para imgenes: Image (una clase de base abstracta para las otras dos
clases), Bitmap y Metafile. Ms adelante analizar la clase Metafile.
Figura 18-7. Un mapa de bits monocromtico 8 8 que contiene una obra de arte.
Debido a que un bit slo puede dar soporte a dos estados, los archivos de mapa de bits de 1 bit
son monocromos, desplegando imgenes que slo usan blanco y negro. Para incluir ms colores,
los mapas de bits agregan planos adicionales. Los planos estn apilados uno encima de otro de
modo que una celda en un plano coincide con la celda en esa misma posicin en todos los dems
planos. Un conjunto de ocho planos da como resultado una imagen de mapa de bits de 8 bits
y da soporte a 256 colores por celda (porque 2planos = 28 = 256). Algunas imgenes incluyen hasta
32 o incluso 64 bits (planos), aunque algunos de estos bits pueden reservarse para fusin alfa,
que hace posible la percepcin de la transparencia.
A menos que sea un fantico de las imgenes, la manipulacin de todos esos bits es una tarea
excesiva. Por fortuna, no tiene que preocuparse por ella, porque todo lo hace la clase Bitmap.
Slo necesita preocuparse por cargar y guardar mapas de bits (empleando los mtodos simples
de Bitmap, por supuesto), empleando un mapa de bits como una brocha o un objeto de dibujo
(como ya lo hicimos en algn cdigo de ejemplo en este captulo), o escribir en la superficie del
propio mapa de bits al adjuntar un objeto Graphics.
Si tiene un mapa de bits en un archivo puede cargarlo mediante el constructor de la clase Bitmap.
Dim bonitaImagen As New Bitmap("BuscarArticulo.bmp")
Para dibujar un mapa de bits en una superficie grfica use el mtodo objeto DrawImage de
Graphics.
e.Graphics.DrawImage(bonitaImagen, leftOffset, topOffset)
En la figura 18-8 se muestra la salida del bloque de cdigo anterior. Pero no es todo el dibujo
que puede hacer. El mtodo DrawImage incluye 30 sobrecargas. Eso me mantendra ocupado
por lo menos por 37 minutos!
Figura 18-8. Tres vistas de un lector; una obra maestra del autor.
' ----- Arco en 90 grados en sentido del reloj para un circulo de 40 pixeles de diametro.
e.Graphics.DrawArc(Pens.Black, 50, 10, 40, 40, 0, -90)
Etctera. Ya se dio una idea. En la figura 18-9 se muestra la salida de este cdigo.
e.Graphics.DrawPath(Pens.Black, laRuta)
End Using
Este bloque de cdigo dibuja una carita sonriente en el lienzo (vase la figura 18-10).
Qu bonito. Por fortuna, hay otros usos para las rutas grficas, algunas de las cuales analizar en
la siguiente seccin.
Durante las operaciones de dibujo, a las regiones en ocasiones se les denomina regiones de
recorte, porque cualquier contenido que se dibuja fuera de la regin es recortado y desechado.
El siguiente cdigo dibuja una imagen, pero enmascarada en una elipse en la parte media al usar
(ta-da!) una ruta grfica para establecer una regin de recorte personalizada:
' ----- Cargar la imagen. Se mostrara mas pequena que lo normal.
Dim ImagenBienvenida As New Bitmap("ImagenBienvenida.jpg")
Dim laRuta As New Drawing2D.GraphicsPath( )
Las regiones tambin son tiles para prueba de golpes. Si dibuja una imagen no rectangular
en un formulario, y quiere saber cuando el usuario hace clic en la imagen, pero no en cual-
quier pxel fuera de sta, puede usar una regin que tenga la forma exacta de la imagen para
probar los clics del ratn.
' ----- Crear una brocha para el color de despliegue, con base
' en el nombre del elemento.
Dim brochaColor As New SolidBrush(Color.FromName( _
CStr(ComboBox1.Items(e.Index))))
Ejecute el cdigo y juegue con el cuadro combinado, como se muestra en la figura 18-14.
</Grid>
</Window>
Este cdigo define la ventana, Window1, que tiene su clase real System.Windows.Window. Los
atributos de la etiqueta Window de XAML, incluidos Title, Height y Width, se asignan a las
propiedades del mismo nombre en la clase Window.
Aadamos un poco de picante a este formulario. Agreguemos un botn que incluye un arcoris
en la superficie de ste, adems de un brillo amarillo alrededor del botn. Agregar un maneja-
dor de eventos que muestre un cuadro de mensaje. Al igual que con una aplicacin estndar de
Windows Forms, se utilizan los controles en el Cuadro de herramientas para generar su formu-
lario. Arrastrar un botn a la superficie del formulario y usar el rea de texto XAML para dar
nueva vida a la ventana.
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="160" Width="411">
<Grid>
<Button Margin="95,26,99,35" Name="Button1">
<Button.Foreground>White</Button.Foreground>
<Button.FontSize>18</Button.FontSize>
<Button.FontWeight>Bold</Button.FontWeight >
<Button.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="Red" Offset="0" />
<GradientStop Color="Orange" Offset="0.1425"/>
<GradientStop Color="Yellow" Offset="0.285"/>
<GradientStop Color="Green" Offset="0.4275"/>
<GradientStop Color="Blue" Offset="0.57"/>
<GradientStop Color="Indigo" Offset="0.7325"/>
<GradientStop Color="Violet" Offset="0.875"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Button.Background>
<Button.BitmapEffect>
<OuterGlowBitmapEffect />
</Button.BitmapEffect> Click Me
</Button>
</Grid>
</Window>
Al ejecutar este programa con la tecla F5 se nos presenta el formulario y el botn esperados, pero,
oh, qu botn tan complejo (vase la figura 18-16).
Aunque el color no aparece en este libro en escala de grises, el formulario tiene un botn con el
arcoris desplegado.
(La parte del atributo de un nombre no debe entrar en conflicto con alguna palabra clave de
Visual Basic.) Los atributos aparecen como metadatos en el ensamblado compilado final, y son
usados por clases y aplicaciones que, por diseo, extraen significado de atributos especficos. En
el cdigo de este captulo usaremos el control PropertyGrid, el control que implementa el pa-
nel Propiedades dentro del entorno de desarrollo de Visual Studio, y suele usarse para modificar
Resumen
Aunque muchas partes de GDI+ son como envolturas alrededor del viejo sistema GDI, GDI+
an se las arregla para proporcionar poder y simplicidad que rebasa la implementacin original.
En el desarrollo de aplicaciones de negocios, no siempre tiene la necesidad de usar los aspectos
ms interesantes del espacio de nombres System.Drawing. Pero cuando lo hace, encontrar un
sistema simple y coherente para despliegue de imgenes, texto y elementos vectoriales personali-
zados en la pantalla u otro medio de salida.
Y hablando de simplicidad y coherencia, busque WPF en un equipo de cmputo cerca de usted.
A medida que ms programadores se vean seducidos por el nuevo sistema, con el tiempo suplan-
tar a Windows Forms y al sistema de pginas ASP.NET como la capa de presentacin principal
en el escritorio .NET y en aplicaciones Web.
Proyecto
El proyecto Biblioteca ha usado caractersticas de GDI+ desde el momento en que apareci el
primer formulario en el proyecto recin creado, pero lleg gratis mediante cdigo incluido en
el marco conceptual. Ahora es tiempo de que usted, el programador, agregue su propia contribu-
cin de GDI+ a la aplicacin. En el cdigo de proyecto de este captulo utilizaremos GDI+ para
mejorar el despliegue normal de un control mediante caractersticas de diseo de propietario.
Adems, por fin empezaremos a implementar parte de las caractersticas de cdigo de barras con
que lo tent en captulos anteriores. Siento decirle que no usaremos la agradable experiencia de
dibujo XML que es WPF.
Proyecto | 511
El formulario BusquedaArticulo.vb tiene un botn Atrs como en los exploradores Web, con una
lista desplegable de entradas recientes. Los elementos agregados a la lista pueden incluir ttulos
y nombres de autor largos. Usemos el nuevo mtodo AcomodarTextoAlAncho para limitar el
tamao de los elementos de texto en esta lista. Abra el cdigo fuente del formulario Busque
daArticulo y localice el mtodo ActualizarBotonesAtras. Cerca de la mitad de esta rutina
se encuentra esta lnea de cdigo:
cualMenu.Text = buscarHistoria.DesplegarHistoria
cualMenu.Text = AcomodarTextoAlAncho(buscarHistoria.DesplegarHistoria, _
Me.Width \ 2, usarLienzo, cualMenu.Font)
Eso limitar cualquier texto de elemento de men a la mitad del ancho del formulario, lo que
parece razonable. Esa variable usarLienzo es nuevo, as que agreguemos una declaracin en la
parte superior del mtodo ActualizarBotonesAtras.
Adems, necesitamos desechar apropiadamente ese lienzo grfico creado al principio del mtodo.
usarLienzo.Dispose( )
Proyecto | 513
Us el texto Ag para asegurarme de que la altura incluya todos los elementos ascendentes y descen-
dentes de la fuente (las partes que sobresalen arriba y abajo de la mayor parte de las letras). Pienso
que el clculo incluira esos valores aunque usara mm para la cadena, pero como digo siempre, es
mejor prevenir que lamentar. Al establecer la propiedad ArticulosCoincidentes.ItemHeight
aqu, se indica el tamao de todos los elementos de la lista. Si hubiera decidido usar elementos de
altura variable en lugar de fija, habra manejado el evento MeasureItem del control. Con los ele-
mentos fijos podemos ignorar ese evento, y pasar al que hace el dibujo real: DrawItem.
He aqu lo que cdigo va a hacer para cada elemento de la lista: 1) crear las brochas y los objetos
de fuente necesarios que usaremos en el dibujo; 2) dibujar las cadenas de texto en el lienzo de
elementos de lista, y 3) limpiar. Debido a que los elementos de la vista tambin pueden estar selec-
cionados o no, llamaremos a algn mtodo proporcionado por el marco conceptual para dibujar
los elementos apropiados de fondo y primer plano que indican las selecciones de elementos.
Cuando dibujamos las columnas de texto mltiples, es posible que una columna sea demasiado
larga e invada el rea de la siguiente columna. Por esto es por lo que escribimos antes la funcin
El cdigo que usar para dibujar cada elemento de la lista ArticulosCoincidentes usar
cdigo como ste. Agreguemos ahora ese cdigo al manejador de eventos ArticulosCoinci
dentes.DrawItem.
' ----- El titulo usara una version en negritas de cada fuente principal.
fuenteNegritas = New System.Drawing.Font(e.Font, FontStyle.Bold)
Proyecto | 515
Lo ve?, es sorprendentemente fcil dibujar cualquier cosa que quiera en el elemento de cuadro
de lista. En este cdigo, la salida real al lienzo mediante GDI+ fue responsable de las cuatro
instrucciones DrawString. Aunque esta base de datos de biblioteca no le da soporte, pudimos
incluir una imagen de cada elemento en la base de datos y desplegarlo en el cuadro de lista, justo
a la izquierda del ttulo. Adems, las llamadas a e.DrawBackground y e.DrawFocusRectangle
permiten que el control resalte apropiadamente el elemento correcto (aunque tuve que elegir la
brocha de texto). En la figura 18-17 se muestran los resultados de nuestra dura labor.
No hay mucho aqu. La clase define dos miembros obligatorios: una propiedad String de slo
lectura llamada ItemType, y un requisito de que la clase derivada proporcione su propia imple-
mentacin para ToString. Las otras cinco clases derivadas de este archivo mejoran la clase base
para dar soporte a los distintos tipos de elementos de despliegue incluidos en una etiqueta de c-
digo de barras. Revisemos brevemente una de las clases, RecArticuloCodigoBarras. Permite
que un rectngulo con relleno opcional aparezca en una etiqueta de cdigo de barras, e incluye
miembros privados que rastrean los detalles del rectngulo.
Public Class RecArticuloCodigoBarras
' ----- Incluye un elemento de rectangulo basico en una
' etiqueta de codigo de barras.
Inherits GenericoArticuloCodigoBarras
Proyecto | 517
El resto de la clase incluye propiedades que proporcionan la interfaz pblica de esos miembros
privados. He aqu el cdigo para la propiedad RellenarColor:
<Browsable(True), DescriptionAttribute( _
"Establece el color de relleno del rectangulo.")> _
Public Property FillColor() As Drawing.Color
' ----- El color de relleno.
Get
Return RellenoColorAlmacenado
End Get
Set(ByVal Value As Drawing.Color)
RellenoColorAlmacenado = Value
End Set
End Property
Como casi todas las dems propiedades, slo recupera el valor privado relacionado. Su declaracin
incluye dos atributos que sern ledos por el control PropertyGrid ms adelante. La propiedad
Browsable dice: S, incluye esta propiedad en la cuadrcula, y DescriptionAttribute esta-
blece el texto que aparece en la parte inferior del rea de ayuda del control PropertyGrid.
Cuando haya usado el panel Propiedades para editar sus formularios, podr establecer colores
para una propiedad de color empleando una herramienta de seleccin de color especial integrada
en la propiedad. Basta con tener una propiedad definida usando System.Drawing.Color para
habilitar esta misma funcionalidad para su propia clase. Cmo funciona? Igual que la propiedad
RellenarColor tiene atributos reconocidos por el control PropertyGrid, la clase System.
Drawing.Color tambin tiene esas propiedades, una de las cuales define una clase de editor de
propiedades personalizada para colores. Su implementacin est ms all del alcance de este libro,
pero de todos modos es estupenda. Si est interesado en hacer esto para sus propias clases, puede
leer un artculo que escrib acerca de los editores de cuadrcula de propiedades hace unos aos.*
Antes de llegar a los formularios de editor, necesito que conozca cuatro funciones de apoyo que
ya agregu al archivo del mdulo General.vb:
Funcin GenerarEstiloFuente
Estilos de fuente (como negritas e itlicas) se establecen en los objetos Font empleando miem-
bros de la enumeracin System.Drawing.FontStyle. Pero cuando se almacena informa-
cin de fuentes en la base de datos, eleg almacenar esas configuraciones de estilo empleando
letras (como N para negritas). Esta funcin convierte las letras al valor FontStyle.
Proyecto | 519
Luego, antes de dibujar los contornos de la vista previa de cada etiqueta rectangular, reubica el
origen de la cuadrcula en la esquina superior izquierda de la hoja de papel en pantalla, y trans-
forma la escala con base en la relacin de una pieza de papel real a la imagen en pantalla.
e.Graphics.TranslateTransform(izquierdaPagina, arribaPagina)
e.Graphics.ScaleTransform(usarRelacion, usarRelacion)
Hay que hacer unos cuantos clculos ms para el tamao de cada etiqueta, seguidos por un do-
ble bucle (para las filas y columnas de etiquetas) que hacen la impresin real de los lmites de la
etiqueta (el clculo de los detalles se omiti para ser breves).
For rastreoFila = 1 To CInt(BCRows.Text)
For colScan = 1 To CInt(BCColumns.Text)
desplazamientoIzquierda = ...
topOffset = ...
e.Graphics.DrawRectangle(Pens.Cyan, _
desplazamientoIzquierda, desplazamientoArriba, _
unTwipsAncho, unTwipsAlto)
Next rastreoCol
Next rastreoFila
Proyecto | 521
El cdigo de cada tipo de elemento realiza las diversas transformaciones de tamao, posicin y
giro necesarias para desplegar apropiadamente el elemento. Echemos una mirada cercana al c-
digo que despliega elementos de texto estticos (cdigo al que tambin se le llama para desplegar
texto de cdigo de barras). Despus de reducir a escala la vista real al rea de vista previa de la
superficie de la etiqueta, cualquier giro solicitado por el usuario es realizado cerca de la esquina
superior izquierda del rectngulo que contiene el texto impreso.
e.Graphics.TranslateTransform(X1, Y1)
e.Graphics.RotateTransform(anguloTexto)
A continuacin, una lnea de guiones grises se dibuja alrededor del objeto de texto para mostrar
su estado seleccionado.
plumaPixeles = New System.Drawing.Pen(Color.LightGray, _
1 / e.Graphics.DpiX)
plumaPixeles.DashStyle = Drawing2D.DashStyle.Dash
e.Graphics.DrawRectangle(plumaPixeles, X1, Y1, X2, Y2)
plumaPixeles.Dispose( )
Despus de establecer algunas marcas para alinear apropiadamente el texto de manera vertical y
horizontal dentro de su cuadro contenedor, el mtodo estndar DrawString echa el texto sobre
la pantalla.
e.Graphics.DrawString(mensajeTexto, usarFuente, _
New System.Drawing.SolidBrush(colorTexto), _
New Drawing.RectangleF(X1, Y1, X2, Y2), formatoTexto)
' ----- Permitir que el usuario edite la lista de etiquetas de codigo de barras.
If (PerfilSeguridad( _
SeguridadBiblioteca.AdministrarPlantillasCodigoBarras) = False) Then
MsgBox(MensajeNoAutorizado, MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If
Proyecto | 523
' ----- Deje que el usuario edite la lista de paginas de codigo de barras.
If (PerfilSeguridad( _
SeguridadBiblioteca.AdministrarPlantillasCodigoBarras) = False) Then
MsgBox(MensajeNoAutorizado, MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
Return
End If
Aunque esta instruccin no es realmente necesaria, encontr que el formulario tenda a pestaear
un poco en algunos sistemas cuando la opacidad iba de 100% (1.0) a cualquier cosa (99%, o
0.99, en este caso). Este parpadeo era menos notorio cuando hice la transicin durante el pro-
ceso de carga.
En el manejador de eventos de AccCerrar.Click incluya este cdigo.
Este cdigo desvanece lentamente el formulario en el curso de 250 milisegundos, en cinco pasos
distintos. Para que el formulario no se cierre abruptamente antes del bonito desvanecimiento,
abra el diseador del formulario, seleccione el botn AccCerrar y cambie su propiedad Dia
logResult a None.
Otra cosa que nunca hicimos fue establecer el cono primario para la aplicacin. Aunque esto
no es estrictamente GDI+, incluye el despliegue grfico, que tiene impacto en la percepcin del
usuario de la calidad del programa. He incluido un cono llamado Libro.ico en el conjunto de
archivos del proyecto. Abra las propiedades del proyecto, seleccione la ficha Aplicacin y use el
campo Icono para buscar el archivo Libro.ico.
Mientras proba el cono, observe que la pantalla de bienvenida apareca (con el cono prede-
terminado de Visual Studio) en la barra de tareas de Windows. En realidad, cada formulario
abierto apareca en la barra de tareas, junto con la entrada del formulario principal. Esto no es el
estndar, y se debe al valor de la propiedad ShowInTaskbar incluida en cada formulario. Me he
tomado la libertad de recorrer todos los formularios (excepto FormularioPrincipal) y estable-
cer esta propiedad en False. La mayor parte de los formularios estaban listos para establecerse
apropiadamente, de modo que alter la docena que no lo estaba.
La aplicacin Biblioteca est realmente empezando a llenarse de caractersticas. En realidad, para
el siguiente captulo, habremos agregado ms de 95% de su cdigo total. Puedo ver la excitacin
en su casa. Siga adelante, d vuelta a la pgina y aada algo al disfrute de su cdigo.
Proyecto | 525
Bienvenue chapitre dix-neuf! Mis disculpas a todos aquellos que no hablan francs (y tambin a
quienes en realidad lo hablan). Me llev cuatro aos completos de idiomas en preparatoria, pero
por alguna razn, no aprend. An puedo recordar algunas frases importantes, como Je suis un
garon y O est le crayon?, pero eso es todo. Incluso leamos Candide y Le Petit Prince en clase,
pero eso no ayuda gran cosa. Tom japons en la universidad, y lo encontr mucho ms fcil de
digerir que el francs, de modo que tal vez deba decir, en cambio .
Como un intento por expandir este libro ms all de las playas de las naciones que hablan ingls
localic el prrafo anterior. En un intento por expandir el atractivo de sus aplicaciones ms all
del mundo de habla inglesa, .NET proporciona caractersticas que le permiten localizar su pro-
yecto en otro idioma, aun despus de que su software se ha compilado y liberado.
La cobertura de todas las caractersticas de localizacin en .NET incluira calendarios basados
en los reinos lunares y del emperador, y sistemas de escritura de derecha a izquierda. En este
captulo slo se cubren algunas de las caractersticas de localizacin de interfaces ms comunes.
Tengo la esperanza de despertar su inters en que rebase los lmites del lenguaje de sus aplica-
ciones, llegando a les toiles.
526
Archivos de recursos
Los archivos de recursos son clave para la localizacin del idioma en programas .NET. Visual
Studio escribir los archivos por usted, pero es bueno saber algo acerca de la manera en que
trabajan, porque tal vez quiera crear sus propios archivos de recursos (si tiene mucho tiempo
en sus manos). La vida de un recurso recorre tres fases, como lo determina el tipo de archivo en
que aparece:
conos
Los conos de programa usados con formularios y la propia aplicacin aparecen como recur-
sos estndar. Los conos tienen una extensin de archivo .ico.
Audio
Recursos que pueden incluir archivos de audio con nombre, con base en contenido de audio
WAV.
Archivos
Si los tipos de archivo de la lista hasta ahora no cumplen sus necesidades, puede incluir
archivos completos de cualquier tipo como un recurso con nombre.
Otros
Ms all de los archivos puede almacenar el contenido de cualquier tipo de datos .NET
vlido como un recurso. Los recursos en un archivo .resx tienen tipos .NET, de modo que
en realidad no hay lmite al tipo de datos que puede colocar all. Tambin puede modificar
el archivo .resx para incluir recursos no estndar. stos se encuentran ms all del alcance
de este captulo.
La ventana de propiedades del proyecto incluye un administrador para recursos de toda la apli-
cacin (vase la figura 19-2). La IDE tambin incluye editores especiales que le permiten editar
tipos de recursos estndar y algunos pocos no estndar.
El objeto My.Resources
Analizamos esto en captulos anteriores, pero como recordatorio puede acceder a los recursos
de una aplicacin mediante el objeto My.Resources. Si tiene un recurso de cadena llamado
LeyendaFormularioPrincipal, la siguiente referencia devuelve su valor:
My.Resources.LeyendaFormularioPrincipal
Todos los recursos tienen fuerte imposicin de tipo. En este caso, LeyendaFormularioPrin-
cipal es de tipo System.Cadena. El recurso de imagen ImagenBienvenida incluido en el
proyecto Biblioteca es declarado como tipo System.Drawing.Bitmap. Debido a que cada re-
curso es de tipo impuesto, puede usar la referencia My.Resources en su cdigo justo como
cualquier dato del tipo de recurso.
En nuevas aplicaciones de Windows Forms, todos los recursos de toda la aplicacin aparecen en
el archivo Resources.resx, encontrados en el directorio My Project dentro del directorio de cdigo
fuente de la aplicacin. Puede verlo en el Bloc de notas, si lo desea. Es un archivo XML muy
grande que no me interesa por el momento, excepto que funciona! He aqu la parte del archivo
Resources.resx del proyecto Biblioteca que especifica nuestros dos recursos existentes. (He dividi-
do algunas de las lneas para que quepa en la pgina.) He resaltado el nombre de cada recurso, y
sus tipos de datos impuestos.
<data name="CuerpoBusquedaArticulo"
type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CuerpoBusquedaArticulo.txt;System.String,
mscorlib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="ImagenBienvenida"
type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\recursos\imagenbienvenida.jpg;System.Drawing.Bitmap,
System.Drawing, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
Cada formulario que agregue a su proyecto tambin tiene su propio archivo de recursos privado.
El que corresponde a Form1 es denominado Form1.resx. Estos archivos terminan siendo una
gran adicin para la localizacin de aplicaciones Windows Forms.
Tras bambalinas, su aplicacin est tomando un mtodo orientado a objetos a la adminis-
tracin de recursos. Se est usando la clase System.Resources.ResourceManager para
localizar y devolver instancias de cada recurso cuando sea necesario. Y esta misma clase toma
decisiones acerca de cules recursos especficos del idioma o la cultura (de las docenas que
estoy seguro que ha agregado a su aplicacin) ser visible para el usuario.
Cuando ejecute el programa, crear una imagen de espejo de cualquier cosa que escriba en el
control TextBox empleando caractersticas GDI+. En la figura 19-4 se me muestra jugando con
el programa en lugar de cumplir la fecha lmite de entrega de este captulo.
Aunque este programa parece interesante, no est completamente globalizado ni localizado. Est
casi globalizado. Todo lo que necesitamos para globalizarlo por completo es jalar el switch en
el formulario que habilita la posterior localizacin. Hacemos esto mediante la propiedad Loca-
lizable. Cambie este propiedad de False a True. Ta-da! Su formulario est globalizado!
Ahora, para la parte 2: localizacin. He aqu los pasos para localizar el formulario:
1. Determine cul idioma o combinacin idioma-cultura desea localizar.
2. Seleccione ese idioma o idioma-cultura de la propiedad Language del formulario. Cuando
abra esta lista de propiedades, incluir slo el idioma, como Francs e idiomas combina-
dos con una cultura o pas, como Francs (Canad). A las solas entradas del idioma se les
conoce como de idioma neutral. Puede usar cualquier tipo de localizacin. Si selecciona,
por ejemplo, francs, los usuarios de su aplicacin en Francia o la parte de Canad que ha-
bla francs usar los recursos en francs. Si localiza usando Francs (Canad), los usuarios
canadienses del francs accedern a los recursos localizados, pero no los usuarios en francs
de Francia.
3. Modifique cualquiera de las propiedades del formulario o sus controles.
Eso es todo. Cada vez que se cambie la propiedad Language a algo diferente de (Default),
Visual Studio empieza a grabar todos los cambios en el formulario y el control en un archivo de
recursos separado especficos del formulario y especficos del idioma o la combinacin idioma-
cultura.
Puede localizar el formulario con varios idiomas. Cada vez que cambie la propiedad Language
a otra seleccin de idioma o idioma-cultura, los cambios al formulario o los controles slo se
aplican a esa seleccin. Cada vez que su cambio se guarde en un archivo de recursos separado.
Observa cmo las etiquetas del idioma japons estn ms alejadas de los campos de texto y espe-
jo? Le preocupa tanto como a m? Para sacarlo de mi mente, cambiar el tamao de dos campos
y los har un poco ms largos al jalarlos a la izquierda, como hice en la figura 19-6.
La parte asombrosa es que si establece de nuevo la propiedad Language del formulario a (De-
fault), no slo las etiquetas regresarn al ingls, sino que los campos de texto y espejo regre-
sarn a sus tamaos naturales. Aunque no he revisado cada propiedad, la caracterstica de
localizacin parece tener impacto en todos los elementos de despliegue de cada control.
Ahora el programa est totalmente localizado para el ingls (el idioma predeterminado) y el ja-
pons. Por lo general, el recurso en japons sera usado slo en un sistema que ejecute la versin
japonesa de Microsoft Windows. Pero podemos forzar al programa para que use el japons al
cambiar la cultura de la interfaz de usuario. En el cdigo de inicio de la aplicacin (la rutina
MyAplicacion_Startup en el archivo ApplicationEvents.vb), agregu el siguiente cdigo:
Private Sub MyAplicacin_Startup(ByVal sender As Object, _
ByVal e As Microsoft.VisualBasic.ApplicationServices. _
StartupEventArgs) Handles Me.Startup
If (MsgBox("Confirme que desee cambiar de ingles a japones.", _
Si omite el nombre de archivo de salida, resgen simplemente reemplazar la extensin .resx con
.resources.
Si tiene varios ensamblados de idioma extranjero (para varios formularios, por ejemplo) genere
archivos de recursos para todos ellos. Luego estar listo para compilar el ensamblado satlite.
Debe ingresar estas lneas como una sola lnea larga. Tengo que dividirla en el libro porque el
editor no quiso hacer uno de esos libros tridimensionales que se publican para nios. No les
gust mi idea del entorno de Visual Studio desplegable interactivo, tampoco (algo relacionado
con mantener el libro a un precio accesible).
Las opciones proporcionadas para al.exe hacen magia:
/target:lib
La parte lib dice: Da salida a un archivo estilo DLL.
/embed
Esta opcin indica cules archivos fuente quiere incluir en el ensamblado de salida. La
primera parte delimitada por comas indica el nombre de archivo fuente. La segunda,
el nombre por el cual ser conocido este recurso en la aplicacin. El nombre debe estar en el
formato nombrebase.nombreCultura.recursos, donde nombrebase es el nombre de la
aplicacin (en el caso de recursos para toda la aplicacin) o el nombre de la clase (calificado
con su espacio de nombres) para una clase especfica, como Form1. Debido a que mi apli-
cacin y su espacio de nombres predeterminado de nivel superior es NombresExtranjeros,
lo he incluido en el componente del nombre. Puede agregar tantas opciones /embed como
archivos de recursos tenga que incluir.
Este bloque de cdigo es casi idntico al usado en el ejemplo anterior, pero estoy llamado a
My.Application.ChangeCulture en lugar de My.Application.ChangeUICulture (la par-
te UI est faltando). Esto cambia la cultura de manipulacin de cadenas en lugar de la de interfaz
de usuario.
Ahora, agregar el siguiente cdigo a la clase Form1:
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
MsgBox(Format("500", "Currency"))
End Sub
En la figura 19-9 se muestran los resultados de este cdigo cuando se ejecuta en los modos de
ingls y japons.
Las bibliotecas de clase del marco conceptual (FCL, Framework Class Libraries) incluyen an
ms caractersticas de administracin de cultura en el espacio de nombres System.Globali-
zation. Las clases en este espacio de nombres le permiten ajustar manualmente la salida de ca-
denas sensibles a la cultura para satisfacer sus necesidades. Casi todas son muy esotricas y estn
orientadas a grupos culturales especficos, de modo que no los analizar aqu.
Resumen
Despus de todo, el mundo es pequeo. Y las caractersticas especficas de la cultura en .NET
han ayudado a que sea de esa manera, por lo menos en su software. An estoy sorprendido de
que sea capaz de usar japons en mi versin en ingls de Microsoft Windows. (Primero tengo que
habilitar el soporte para idiomas del este de Asia en la applet Configuracin regional y de idioma
del Panel de control.) Y ahora no slo es Windows o Microsoft Office el que puede cambiar au-
tomticamente con la cultura actual. Los polticos pueden hacerlo, tambin. Perdn, quiero de-
cir que sus propias aplicaciones pueden hacerlo, tambin. Al aprovechar los recursos especficos
de la cultura y las caractersticas de formato automtico y manual incluidas con .NET, pronto
estar vendiendo sus inteligentes aplicaciones de negocios en seis de los siete continentes.
Acceso al proyecto
Cargue el proyecto Cap19 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap19 (Final) cdigo.
Cada instancia de esta clase identifica las multas cobradas y los pagos por un artculo especfico
de la biblioteca (tituloArticulo) y para el cliente que entreg tarde el artculo (IDCopia-
Cliente).
Proyecto | 539
ErrorHandler:
ErrorGeneral("CalcularMultasCliente", Err.GetException(
))
Return 0@
End Function
Es cdigo muy bsico, en realidad, porque la base de datos hace todo el trabajo de sumar los va-
lores. Revis la documentacin de la base de datos y confirm que Multa y Pagado son campos
obligatorios, y nunca sern NULL. Esto mantiene bien el cdigo SQL.
tendrn que proporcionar una entrada ms correcta de su nombre. (Si dos clientes tienen el
mismo nombre tendrn que depender de cdigos de barras; pero este programa es para una
pequea biblioteca, de modo que los nombres en conflicto deben ser raros.)
Los administradores ingresan el nombre del cliente o el cdigo de barras, pero no necesitan
contrasea. Si hay varias coincidencias, el formulario presenta todos los nombres coinciden-
tes en una lista, y el administrador puede seleccionar la entrada correcta de la lista. Esto le
da a un administrador acceso completo a todos los registros del cliente. Obviamente, resulta
importante para un administrador cerrar una sesin cuando termine de usar una estacin
de trabajo que est disponible para clientes.
El mtodo SeleccionarCliente del formulario AccesoCliente proporciona la interfaz al
formulario para administradores y clientes comunes. La funcin devuelve el ID del cliente selec-
cionado, o -1 si el usuario no tuvo acceso correcto al registro de un cliente.
Proyecto | 541
Cada registro de la tabla PagoCliente incluye una fecha de transaccin, la cantidad de sta,
comentarios adicionales y la identidad del usuario administrativo que registra la entrada. Para
aclarar un poco ms el cdigo, los cdigos de letras en la tabla de datos se conviertan a valores
numricos a partir de la enumeracin EventEntryType.
Private Enum TipoEntradaEvento
NoDefinido
PagoCliente
MultaAgregada
MultaDesechada
ReembolsoACliente
MultasAdeudadas
End Enum
La entrada MultasAdeudadas permite que el valor CopiaCliente.Multas sea parte del histo-
rial financiero desplegado en el formulario.
El bibliotecario usa los campos en la seccin Nuevo evento de pago del formulario PagoClien-
te para agregar registros de cobro y pago. Todos los registros agregados previamente aparecen en
la lista HistoriaEventos, en la seccin Historia de eventos de pago.
El formulario que llama (agregado ms adelante en este captulo) necesita pasarse en el valor
CopiaCliente.ID para identificar el registro apropiado. Pero el plan es hacer que los pagos
agregados en este formulario fluyan de regreso al formulario principal. Los dos formularios
compartirn un conjunto de objetos de PagoArticulo empleando la clase que agregamos hace
unas cuantas secciones en este captulo. Las almacenaremos en una variable de miembro local
como un conjunto genrico.
Proyecto | 543
Este mtodo registra el nmero de ID de la copia del cliente y el cobro de pagos para el artculo
prestado. Entonces el procesamiento pasa al manejador de eventos Load. Es en esta rutina donde
agregamos nuestro cdigo de administracin financiera localizada. En la rutina PagoClien-
te_Load recorra hacia abajo hasta la tercera parte del mtodo, al cdigo que carga los detalles
de resumen de la base de datos. Justo despus de la lnea:
RegistroArticulo.Text = CStr(infoBD!Titulo)
Agregue las instrucciones que formarn globalmente los valores de moneda para las etiquetas de
resumen Multas, Pagos y Saldo que aparecen cerca de la parte superior del formulario.
multaOriginal = CDec(infoBD!Multa)
RegistroMulta.Text = Format(multaOriginal, "Currency")
RegistroPagos.Text = Format(CDec(infoBD!Paid), "Currency")
saldoAdeudado = multaOriginal - CDec(infoBD!Paid)
RegistroSaldo.Text = Format(saldoAdeudado, "Currency")
El resto del cdigo del manejador de eventos Load carga registros existentes de la tabla Pago-
Cliente, adems de la multa adeudada original, si la hay, del campo de la base de datos Co-
piaCliente.Multa.
Ms adelante, cuando el usuario hace clic en el botn Agregar para agregar un nuevo evento fi-
nanciero a la entrada de cliente y copia de artculo, la rutina GuardarDatosEvento (equivalente
al mtodo GuardarDatosFormulario en casi todos los dems formularios que hemos desarro-
llado hasta ahora) guarda la informacin actualizada en la base de datos. Esta rutina debe guardar
el nuevo cobro o pago en la tabla PagoCliente, adems de actualizar el resumen de cobro y pago
en el registro CopiaCliente. Agregue el cdigo que escribe esos registros, justo despus de los
clculos para las variables montoMulta y montoPagado en el mtodo GuardarDatosEvento.
He dividido ambas instrucciones de base de datos en una transaccin para ayudarle a asegurar
la integridad de los datos. Una vez que se haya actualizado, es hora de actualizar la pantalla. La
lista en pantalla de cobros y pagos requiere este nuevo registro. La lista usa la clase local Histo-
riaEventosArticulos, una variacin de la clase DatosListaElementos que suele usar con-
troles ListBox. HistoriaEventosArticulos tiene campos que son especficos para desplegar
informacin financiera en el cuadro de lista HistoriaEventos. Agregue el cdigo que genera
un registro HistoriaEventosArticulos y agrguelo a la lista HistoriaEventos, inmediata-
mente despus del cdigo que actualiza la base de datos que acabamos de agregar.
Este cdigo es seguido por cdigo similar que actualiza la lista SoloPagos, la Generic.List(Of
PagoArticulo) que fue pasada del formulario que llama. El cdigo actualiza el registro de re-
sumen del pago existente o agrega un nuevo registro a la lista genrica.
Proyecto | 545
Antes de dejar esta funcin, necesitamos actualizar los tres valores de resumen financieros cerca
de la parte superior del formulario, los que establecimos cuando se carg por primera vez el for-
mulario. Agregue este cdigo justo despus de la lista actualizada PaymentSolo.
El botn Imprimir boleta de saldo genera un recibo impreso de todas las multas y pagos del
cliente. Agregaremos su cdigo en un captulo posterior.
Casi todo el cdigo de este formulario existe para administrar multas y pagos. Para agregar un
cobro o pago, el bibliotecario selecciona un artculo de la lista Multas y luego hace clic en el
botn Multas y pagos. Esto despliega el formulario Pago del cliente que acabamos de agregar.
Las dos listas principales del formulario Registros del cliente aprovecharn la clase estndar Datos-
ListaElementos y usarn una clase ms rica en propiedades para dar soporte a las necesidades de
Proyecto | 547
Ahora, regrese al formulario RegistrosCliente. Como puede saber al revisarlo, la lista Multas
despliega varias columnas de valores monetarios. Agreguemos el cdigo que forma correctamen-
te la moneda de acuerdo con los parmetros monetarios regionales. En primer lugar, localice el
mtodo ActualizarMultasClientes. Esta rutina agrega todas las multas y pagos, y despliega
el resultado a travs del control Label SaldoAdeudo.
Cerca de la parte superior de esta rutina hay un comentario que establece Limpiar la lista ac-
tual. Agregue el cdigo siguiente justo despus del comentario.
Multas.Items.Clear()
saldoTotal = 0@
SaldoVencido.Text = Format(0@, "Currency")
Me.Cursor = Windows.Forms.Cursors.WaitCursor
Este bloque forma de manera apropiada cada valor de moneda. Como opcin predeterminada,
todos los montos adeudados aparecen en rojo en la lista. La ltima lnea de este bloque de cdigo
restablece el color a uno del elemento de lista si no hay saldo adeudado.
Todo lo que necesitamos hacer es agregar un manejador de eventos para el botn Cliente. Ubi-
que el manejador de eventos AccClienteAcceso_Click en el cdigo del formulario. Luego
agregue el siguiente cdigo a ese manejador.
Proyecto | 549
Este cdigo hace llamadas directas a dos de los formularios que agregamos en este captulo:
AccesoCliente y RegistrosCliente. Primero pide al usuario que seleccione un registro de
cliente y luego despliega sus detalles mediante el formulario Registros del cliente.
Esto es correcto y est bien, pero tal vez est pensando Ahora el formulario Cliente le per-
mite abrir el formulario Registros del cliente. Y ese formulario tiene un botn Editar que le
permite una vez ms abrir el formulario Cliente. Si fuera un falso bibliotecario, puede haber
millones de formularios de administracin de clientes en pantalla a la vez. Y es cierto. As que
tenemos que agregar algn cdigo para evitar que eso suceda. El segundo argumento False de
RegistrosCliente.ViewRegistrosCliente es una marca que dice: No muestres el botn
Editar en el formulario Registros del cliente. Existe cdigo similar en el formulario Registros del
cliente que detiene la recursin.
Private Sub AccEditarCliente_Click...
If ((New Cliente).EditarRegistroLimitado( _
ActivePatronID) <> -1) Then...
Podra cambiar esto a Short Date o cualquier otra configuracin de cultura neutral. El mtodo
que elija en realidad depender de su audiencia de destino. Y si a esa audiencia le gusta lo escrito
en el papel, el siguiente sobre impresin es para usted.
Proyecto | 551
552
.NET/GDI+
Impresin de un documento
Ya vimos que muchos componentes de Windows funcionan juntos para generar su salida im-
presa. Dentro de su cdigo .NET, tambin usar muchos componentes (clases) para orientar el
proceso de impresin. Cuatro pasos principales intervienen en la impresin de un documento
(al menos de manera directa) a partir de su cdigo:
1. Crear una instancia de una clase PrintDocument (o agrguela como un control a su formu-
lario).
2. Establecer los diversos parmetros de impresora de PrintDocument, ya sea mediante una
clase o control PrintDialog (o relacionado), o usando las configuraciones manual o pre-
determinada.
3. Agregar un manejador de eventos para el evento PrintPage de PrintDocument. A este
evento se le llama una vez por cada pgina, y recibe un objeto System.Drawing.Graphics
para el lienzo de la impresora. Su cdigo de manejador de eventos imprime una sola pgina
y actualiza una marca que le indica al documento si habr ms pginas.
4. Llamar al mtodo Print de PrintDocument para que la rueda empiece a girar.
Estos controles implementan los dos primeros pasos del proceso de impresin de cuatro pasos.
A continuacin agregaremos el cdigo fuente.
Public Class Form1
Private CualPagina As Integer
Hey!, eso es ms simple que el cdigo que inicia la impresin para la impresora real, aunque
la tecnologa de vista previa pare ser ms compleja que la simple impresin. Incluso debe
haber una ley contra esta simplicidad. Por fortuna, no la hay. En la figura 20-7 se muestra la
ventana de vista previa, despus de usar el botn de la barras de herramientas de dos pginas
a la vez.
Profundicemos un poco ms en lo simple que es este cdigo. Puedo aceptar que la clase
PrintPreviewDialog incluya mucho cdigo sorprendente para salida impresa de la vista
previa. Pero la parte notable del cdigo es que no tuvimos que reescribir la lgica personali-
zada de dibujo de GDI+ que ahora dirige el despliegue de vista previa y la salida real. Todo
lo que necesitbamos hacer era asignar el objeto PrintDocument al control de cuadro de
dilogo correcto.
ImpresoraUsuario.AllowSomePages = True
DocCuenta.PrinterSettings.MinimumPage = 1
DocCuenta.PrinterSettings.MaximumPage = 5
DocCuenta.PrinterSettings.FromPage = 1
DocCuenta.PrinterSettings.ToPage = 5
If (ImpresoraUsuario.ShowDialog() = _
Windows.Forms.DialogResult.OK) Then _
DocCuenta.Print()
End Sub
Cuando esta vez el usuario haga clic en el botn Imprimir, la seccin Imprimir rango del cuadro
de dilogo tiene habilitado el campo Pginas, y se han llenado ya los campos de pginas mximas
y mnimas en el rango 1-5 (vase la figura 20-8).
Si el usuario ajusta este campo a 1-6, ocurre un error que establece que el rango vlido slo se
encuentra entre 1-5. Pero si selecciona Todas las pginas o 1-5 o 1-4 o 2-3 o Pgina actual o
Seleccin, el manejador de eventos PrintPage ser llamado exactamente de la misma manera.
En realidad, el manejador ser llamado docenas, incluso cientos de veces hasta que le diga que se
detenga. La seleccin del usuario tiene impacto en la propiedad PrinterSettings.PrintRan-
ge y algunas otras propiedades, pero no tiene un impacto directo en el proceso de impresin.
Depende de usted modificar el comportamiento de impresin de estos parmetros.
Imaginemos que el usuario ingres un rango de impresin 2-3. No podemos dejar que Print-
Document dispare el evento PrintPage para las cinco pginas porque, aunque generemos la
salida slo para las pginas 2 y 3, aun tendremos tres pginas en blanco fuera de la impresora. Lo
que queremos es hacer que el evento slo se dispare una vez para la pgina 2 y otra para la pgina
3. Necesitaremos ajustar el uso de la variable de rastreo en el nivel de la clase CualPagina para
Debido a que el cdigo de vista previa de impresin comparte la misma configuracin de documen-
to, necesitamos ajustar el cdigo de vista previa para forzarlo a imprimir siempre todas las pginas.
Private Sub AccVistaPrevia_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles AccVistaPrevia.Click
' ----- Desplegar una vista previa del documento.
VistaPreviaUsuario.Document = DocCuenta
DocCuenta.PrinterSettings.PrintRange = _
Printing.PrintRange.AllPages
VistaPreviaUsuario.ShowDialog( )
End Sub
Si ejecuta el programa y ajusta el rango de impresin, debe ajustar las pginas que solicit. He
colocado una copia de este programa en el directorio de instalacin del libro. Lo encontrar en
el subdirectorio Prueba de vista previa de impresin.
Resumen
Le recomiendo que estudie con cuidado las clases y controles especficos de la impresora y que
los analice en este captulo. Se incluyen muchas propiedades que le permiten afinar la salida de
su pgina impresa con base en los parmetros especificados por el usuario. Por ejemplo, le pro-
met al principio de este captulo que podra descubrir si una impresora era a color. La propie-
dad PrinterSettings.SupportsColor le da una respuesta simple de s o no a esta pregunta
caracterstica. Si sabe que una impresora no soporta color, puede ajustar su cdigo PrintPage
para presentar el contenido de pgina en un formato ligeramente diferente.
Proyecto
Como se anunci, el proyecto de este captulo se concentra en los recibos de salida y pago de
multa. Pero tambin agregaremos todo el cdigo que permite a los clientes y bibliotecarios dar
entrada y salida a libros y otros artculos de la biblioteca.
Acceso al proyecto
Cargue el proyecto Cap20 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap20 (Final) cdigo.
Imports System.Runtime.InteropServices
<DllImport("winspool.Drv", EntryPoint:="OpenPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function OpenPrinter(ByVal src As String, _
ByRef hPrinter As IntPtr, ByVal pd As Long) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="ClosePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function ClosePrinter( _
ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="StartDocPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Proyecto | 565
<DllImport("winspool.Drv", EntryPoint:="EndDocPrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function EndDocPrinter( _
ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="StartPagePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function StartPagePrinter( _
ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="EndPagePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function EndPagePrinter( _
ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="WritePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function WritePrinter( _
ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, _
ByVal dwCount As Int32, ByRef dwWritten As Int32) _
As Boolean
End Function
Proyecto | 567
Usaremos esta clase para comunicar los detalles que se imprimirn en el recibo cuando se presten
artculos. Hablando de la impresin de la boleta, agreguemos la clase que hace la impresin real.
Cree un nuevo archivo de mdulo (no una clase) llamado ImpresionBoleta.vb. Reemplace su
definicin de mdulo vaca con el fragmento de cdigo siguiente.
ErrorHandler:
ErrorGeneral("ImpresionBoleta.ImprimirBoletaPrestamo", _
Err.GetException())
Return
End Sub
Proyecto | 569
El cdigo del botn Imprimir es casi exactamente el mismo, pero usa una instancia de PrintDia-
log en lugar de una de PrintPreviewDialog. Tambin lleva registro del nmero de cdigo de
barras impreso, de modo que puede ayudar a evitar la sobrecarga la prxima vez que se imprimen.
El manejador de eventos DocumentoCodigoBarras_PrintPage hace la impresin real del
cdigo de barras. Su cdigo combina los manejadores de eventos EtiquetaCodigoBarras.
PreviewArea_Paint y PaginaCodigoBarras.PreviewArea_Paint en una gloriosa m-
quina de impresin.
Para habilitar el uso del formulario de impresin de cdigo de barras, agregue las siguientes
instrucciones al manejador de eventos AccCodigoBarrasInformes_Click en la clase Formu-
larioPrincipal.
Proyecto | 571
El cdigo hace algunos clculos para determinar la nueva fecha de vencimiento (evitando los das
festivos), y luego actualiza la base de datos en una transaccin.
EmpezarTransac()
ConfirmarTransac()
Usted pasa esta funcin al ttulo proporcionado por el usuario (buscarTexto) y una marca
indicando devolucin o prstamo, y devuelve el campo CopiaArticulo.ID de la base de datos
para el artculo seleccionado de la biblioteca.
Todos los cambios restantes en este captulo ocurren en la clase FormularioPrincipal, as que
pasemos all ahora. El mtodo ActualizarDespliegueParaUsuario ajusta las caractersticas
del formulario principal cuando un administrador inicia o termina sesin. Una caracterstica
que no tomamos en cuenta antes es la capacidad definida del administrador para que los clientes
pidan prestados los artculos sin ayuda del bibliotecario. Para dar soporte a esa caracterstica, ne-
cesitamos cambiar parte del cdigo en el mtodo ActualizarDespliegueParaUsuario. Unas
diez lneas de cdigo abajo, en la seccin condicional que configura el despliegue para cliente,
encontrar estas cuatro lneas:
Proyecto | 573
EtqTareas.Visible = usuarioPuedePrestarse
LineaTareas.Visible = usuarioPuedePrestarse
ImgSalida.Visible = usuarioPuedePrestarse
AccSalida.Visible = usuarioPuedePrestarse
Tambin necesitamos agregar cdigo relacionado con seguridad similar al mtodo TareaSali-
da. He aqu las primeras lneas del cdigo de ese mtodo:
' ----- Actualizar el despliegue.
AllPanelsInvisible()
If (PerfilSeguridad(SeguridadBiblioteca.ArticulosPrestados)) Then _
PanelSalida.Visible = True
' ----- Ver si los patrones pueden sacar elementos por si solos.
usuarioPuedePrestarse = CBool(Val(ObtenerValorSistema ("SalidaCliente")))
El prstamo real de artculos ocurre en el propio formulario principal. En primer lugar, se iden-
tifica un cliente, y se procesan los artculos que se prestarn. Agreguemos una variable en el nivel
de la clase a FormularioPrincipal para llevar registro del cliente. Y siempre y cuando estemos
agregando definiciones, tambin agregaremos dos constantes que hagan referencia a las imge-
nes almacenadas en el control FormularioPrincipal.ImagenesEstatus. Estas constantes se
Cuando el usuario identifica al cliente al que se har el prstamo, y luego inicia el prstamo
de artculos, el ltimo paso es hacer clic en el botn Finalizar, indicando el final del proceso de
prstamo para ese cliente. (Vaya a la figura 20-11, si quiere ver ahora el botn Finalizar.) Sin
embargo, no hay nada para evitar que el usuario salte a otra parte del programa, o que salga del
programa por completo, sin hacer primero clic en el botn Finalizar. Debemos anticipar este
comportamiento descorts tan tpico de los usuarios de software. Para asegurar que el proceso de
salida se complete de manera apropiada, agregaremos algn cdigo a tres lugares de Formula-
rioPrincipal que debe capturar cualquier accin descorts del usuario. Agregue el siguiente
cdigo al principio de estos tres mtodos: 1) El manejador de eventos FormularioPrinci-
pal_FormClosing; 2) el mtodo MostrarFormularioInicio, y 3) el mtodo AllPanels
Invisible.
Prstamo de artculos
Todo el cdigo de prstamo (excepto el del formulario BuscarEntregaPrestamo.vb) aparece en la
clase del formulario principal. La salida o prstamo es uno de los ocho paneles principales de
despliegue a los que se accede a travs de este formulario (vase la figura 20-11).
He aqu el proceso para pedir prestados libros del panel de prstamo:
1. El usuario hace clic en el botn Cliente e identifica al cliente que quiere pedir prestados los
artculos.
2. El usuario ingresa el ttulo o el cdigo de barras de cada elemento que se llevar y hace clic
en el botn Salida de cada uno.
3. El usuario hace clic en el botn Finalizar cuando est completado el proceso de salida.
Proyecto | 575
Agreguemos el cdigo para cada uno de estos tres botones. Primero, agregue el cdigo al mane-
jador de eventos AccClienteSalida_Click.
Este cdigo pide la seleccin del usuario y despliega los campos restantes, si tiene xito. He aqu
la parte del cdigo que hace la peticin:
' ----- Obtener el ID del cliente.
idCliente = (New AccesoCliente).SeleccionarCliente()
If (idCliente = -1) Then Return
Como mencion antes, este cdigo diferencia entre entrada numrica (cdigos de barras) y otras
entradas (ttulos).
If (IsNumeric(Trim(CodigoBarrasSalida.Text))) Then
' ----- Tal vez hay un codigo de barras proporcionado. Obtener el ID
relacionado.
textoSql = "SELECT ID FROM CopiarArticulo WHERE CodigoBarras = " & _
TextoBD(Trim(CodigoBarrasSalida.Text))
idCopia = ObtenerEnteroBD(EjecutarSQLRegresar(textoSql))
If (idCopia = 0) Then
' ----- Codigo de barras no valido.
MsgBox("No se encuentra el codigo de barras.", MsgBoxStyle.OkOnly Or _
MsgBoxStyle.Exclamation, TituloPrograma)
CodigoBarrasSalida.Focus()
CodigoBarrasSalida.SelectAll()
Return
End If
Else
' ----- Buscar por titulo.
idCopia = (New BuscarEntregaPrestamo).RevisarArticulosPorTitulo(False, _
Trim(CodigoBarrasSalida.Text))
If (idCopia = -1) Then Return
End If
Con el tiempo, despus de verificar que el archivo est disponible para uso del cliente, el cdigo
da la salida al artculo al actualizar los registros relevantes en la base de datos.
EmpezarTransac()
ConfirmarTransac()
El ltimo de los tres botones es Finalizar. Agregue el cdigo al manejador de eventos AccFi-
nalizarSalida_Click.
Proyecto | 577
Este cdigo simplemente restablece los campos de despliegue en preparacin del siguiente prs-
tamo del cliente.
El cuadro de lista del panel de salida necesita desplegar dos columnas de datos: 1) la fecha de
vencimiento, y 2) detalles del archivo, como ttulo y cdigo de barras. Estos valores se agregaron
a la lista empleando la clase ArticuloPrestado que agregamos un poco antes en el captulo.
Agregue cdigo al manejador de eventos ArticulosPrestados_DrawItem.
Devolucin de artculos
Devolver los artculos es mucho ms simple porque no necesitamos identificar primero al cliente.
El cdigo de barras o el ttulo del artculo devuelto bastan para completar todo el procesamiento.
En la figura 20-12 se muestra el panel Entrada que muestra el panel para devolucin de libros.
La entrada real ocurre cuando el usuario ingresa un cdigo de barras o ttulo en el campo de texto y
hace clic en el botn Entrada. Agregue el cdigo al manejador de eventos AccEntrada_Click.
Proyecto | 579
ConfirmarTransac()
Para el desarrollador de aplicaciones de negocios, los informes son inevitables. Tal vez quiera
dedicar su tiempo a desarrollar agradables interfaces de usuario o a imaginar los algoritmos
centrales usados por lo general en los principios aceptados de contabilidad. En cambio, invierte
muchas aburridas horas de cada semana a crear informe tras informe. Y estos informes toman un
nmero importante de vctimas en la comunidad de la programacin. Slo en Estados Unidos,
los Centros para el Control y la Prevencin de Enfermedades estiman en casi 850 las muertes
al ao relacionadas con los informes, y ni siquiera toman en cuenta a quienes los leen. Una vez
tuve un cliente que imprima 20 copias de un informe de 600 pginas al mes para sus admi-
nistradores de nivel superior. Claramente estupefacto por la cantidad de pulpa de rboles usada
para generar este informe, la persona fue incapaz de salir con un nombre ms interesante que
informe mensual.
De modo que si usted es un programador de negocios, los informes son su futuro. Pero mientras
sus predecesores tenan que lidiar con lenguajes como RPG III, usted acostumbra usar .NET.
Hey!, despus de todo no es necesario que los informes sean tan malos. Y aun sin depender
de herramientas de creacin de informes de terceros, Visual Studio y .NET incluyen varias
caractersticas y herramientas concentradas en los informes que puede usar en cuanto instala el
programa.
En este captulo se analizan algunos de los recursos de creacin de informes, y se profundiza un
poco en los controles para informes usados en el Proyecto Biblioteca.
581
Documentos XPS
La base de presentacin de Windows (WPF, Windows Presentation Foundation) se usa prin-
cipalmente para que su interfaz de usuario baile con color y accin. Pero una parte de esa tec-
nologa existe para generar documentos estticos tipo XML conocidos como XPS (XML Paper
Specification, especificacin XML para el papel). De la misma manera en que puede generar
informes con HTML, puede hacerlo con el estndar XPS.
En el captulo 18 se incluye un breve anlisis de WPF y XPS. Si la generacin de informes en
XPS le parece interesante, revise la documentacin incluida con Visual Studio.
Crystal Reports
Si tiene por lo menos la Professional Edition de Visual Studio 2008, recibi una copia de gracia
de Crystal Reports. La versin incluida es un subconjunto funcional de la versin oficial de
Crystal Reports 2008. Si es nuevo en Visual Basic, tal vez se haya saltado las versiones anteriores
de Crystal Reports que se han incluido con el lenguaje desde sus primeras versiones. Debido a
esta relacin de largo tiempo con Visual Basic, Crystal Reports se ha vuelto uno de los paquetes
de creacin de informes de uso ms amplio en el mercado.
Crystal Reports es un producto de terceros, que es propiedad de una empresa llamada Business
Objects. El producto ha cambiado de propietario varias veces desde que se asoci con Visual
Basic, pero al parecer Business Objects se est ocupando de ello por el momento. No analizar
ms Crystal Reports en este libro.
Figura 21-1. El BibliotecaDataSet como un origen de datos, y como un archivo XML .xsd.
Haga clic en el botn Agregar para insertar el informe en el proyecto. Aparece un nuevo archivo
Report1.rdlc en su proyecto, y su diseador se abre automticamente. RDLC es la abreviatura de
lenguaje de definicin de informes de cliente (Report Definition Lenguaje Client) y los archivos
de este tipo contienen XML que describe el diseo de un informe diseado en el equipo local. En
la figura 21-3 se muestra el diseador para el archivo Report1.rdlc agregado, adems de los contro-
les en la barra de herramientas que puede agregar a la superficie del informe. Har referencia a los
informes creados mediante este diseador como informes RDLC en el resto de este captulo.
Cuando arrastramos el campo del origen de datos al control Lista, Visual Studio establece un
vnculo entre ellos. El campo DataSetName del control list1 ahora hace referencia a Biblio-
tecaDataSet_Actividad, el nombre del origen de datos. Tambin se agrega un control Text-
Box a la superficie de la lista, y se agrega una expresin (=Fields!NombreCompleto.Value)
que despliega el contenido del campo de la base de datos para cada registro procesado.
Voy a cambiar el tamao del control Lista, el cuadro de texto y la banda Cuerpo para que el campo
del cuadro de texto NombreCompleto sea casi todo lo que hay en informe (vase la figura 21-5).
El informe est listo para usarse. Mientras disebamos la superficie del informe, Visual Studio
estaba ocupado generando XML y almacenando en el archivo Report1.rdlc.
S, tal vez no comprendo bien. Pero es correcto. Visual Studio conect todo.
Desde este men, seleccione Encabezado de pgina, luego despliegue el men de nuevo y selec-
cione Pie de pgina. Cada nueva banda aparece en la superficie del informe.
Si es texto esttico, sin cambio, o texto que se genere dinmicamente a partir de un origen de da-
tos, el control Cuadro de texto es el que debe elegir para mostrar el contenido de texto. Agre-
gue un control Cuadro de texto del cuadro de herramientas para las secciones de encabezado
y pie de pgina. Haga clic dentro del cuadro de texto del encabezado y escriba lo siguiente:
="El informe de la tabla Actividad"
Puede usar el panel Propiedades para ajustar el aspecto de este control, incluida su fuente de
despliegue.
En el cuadro de texto del pie, agregue este texto:
="Page " & Globals!PageNumber
Esta expresin le indica al control list2 que agrupe sus resultados de detalle por el primer ca-
rcter del campo de nombre.
En este mismo formulario, agregue el siguiente texto al campo Etiqueta de mapa de documento:
="Letter: " & Left(Fields!NombreCompleto.Value, 1)
El mapa de documento habilita una lista de hipervnculo en que se puede hacer clic en los dife-
rentes grupos del informe. Cuando ejecutemos el informe un poco despus, veremos este mapa
a la izquierda de la superficie de despliegue del informe.
Los registros de la tabla Actividad estn ordenados para conveniencia del programador (yo). Pero el
usuario del informe tal vez quiera verlos ordenados en la misma manera razonable. Haga clic en la fi-
cha Ordenacin y agregue el siguiente texto en el campo Ordenar por, en la columna Expresion:
=Fields!NombreCompleto.Value
Como es de esperar, esto ordenar los datos por el campo NombreCompleto. Haga clic en los bo-
tones Aceptar hasta salir de todos los cuadros de dilogo y regresar a la superficie del informe.
An necesitamos agregar algo que har que cada grupo se destaque. Agregue un control Cuadro
de texto al control de agrupacin list2. Pngalo en la esquina superior izquierda de ese con-
trol principal, y escriba el siguiente texto en l (o en su propiedad Value):
=Left(Fields!NombreCompleto.Value, 1)
En la seccin Proyecto de este captulo escribiremos un informe que usa fechas de vencimiento
para artculos prestados. Si el artculo se encuentra vencido, quiero mostrar la fecha de venci-
miento en rojo. Por lo general, la propiedad Color del control Cuadro de texto (que controla
el color de fuente) es Black. Para que el campo responda a los artculos vencidos, reemplazar
Black con la siguiente expresin:
=IIf(Fields!FechaVencimiento.Value < Today, "Red", "Black")
Los campos expuestos deben ser propiedades, y no slo campos pblicos; el visor de informes no
reconoce campos de miembro estndar.
Si revisa el cdigo fuente de Form1, encontrar que el cdigo siguiente se agreg al manejador de
eventos Form_Load cuando vinculamos el visor del informe con el informe RDLC:
Me.ActivityTableAdapter.Fill(Me.BibliotecaDataSet.Actividad)
Me.ReportViewer1.RefreshReport()
Es la primera lnea que carga los datos de la tabla Actividad de la base de datos Biblioteca, y lo
vincula con el informe. Necesitamos reemplazar estas dos lneas generadas por el asistente con
cdigo que corte los datos reales a cada paso.
' ----- Crear una tabla falsa de registros falsos.
Dim origenFalso As New Collections.Generic.List( _
Of RegistroActividadFalso)
Ahora puede arrastrar y colocar este campo NombreCompleto del origen de datos en la superficie
de diseo del informe RDLC. Agregue un nuevo informe a su proyecto y siga los mismos pasos
que usamos antes para disear el primer informe. Esta vez, use el origen de datos RegistroAc-
tividadFalso en lugar de BibliotecaDataSet.
Para probar este nuevo informe, elimin el Form1 original del proyecto y agregu un nuevo
Form1. Tambin agregu un control MicrosoftReportViewer a su superficie y lo ancl, pero
no lo vincul con el informe RDLC. Esto mantiene las cosas un poco ms limpias mientras que
no hay controles de origen de unin y cosas por el estilo de qu preocuparse. Luego agregu este
cdigo al manejador de eventos Load:
' ----- Vincular con el diseo del informe RDLC.
Me.ReportViewer1.LocalReport.ReportEmbeddedResource = _
"InformeSimple.Report2.rdlc"
' ----- Generar un nuevo origen de datos. Recuerde que debe tener
' el mismo nombre.
Dim origenInformeFalso As New _
Microsoft.Reporting.WinForms.ReportDataSource
origenInformeFalso.Name = "InformeSimple_RegistroActividadFalso"
origenInformeFalso.Value = origenFalso
Es muy similar al cdigo personalizado anterior, aunque el nombre del origen de datos es ahora
InformeSimple_RegistroActividadFalso, el nombre que este nuevo informe espera (lo que
encontr al ejecutar el informe y leer el mensaje de error).
He guardado una copia de ambos informes personalizados en el directorio de instalacin de los
ejemplos de cdigo fuente del libro. Bsquela en el subdirectorio llamado InformeSimple.
Resumen
Aunque este captulo incluy muchas bonitas imgenes y una gran cantidad de instrucciones,
slo rascamos la superficie de las caractersticas disponibles en los controles de informes in-
cluidos con .NET. Pienso que me rasp el cerebro cuando trat de estudiar cada caracterstica
disponible, pero tal vez su cerebro est mejor preparado para la tarea. An as, si no lo encuentra
exactamente a su gusto, puede usar una de las dems caractersticas de creacin de informes que
present al principio del captulo, o an optar por una solucin de terceros.
Los informes son una parte importante de la vida diaria del desarrollador de negocios. Encon-
trar la herramienta correcta de informes y sentirse cmodo con sus caractersticas no slo es
una buena sugerencia, es necesario en el mundo de los usuarios de software hambrientos de
informes.
Proyecto
Cuando dejamos por ltima vez el documento Kit de recursos tcnicos para el Proyecto Biblio-
teca, inclua cinco informes integrados:
Informe #1: Informe de artculos prestados
Informe #2: Informe de artculos vencidos
Informe #3: Informe de artculos faltantes
Informe #4: Informe de multas adeudadas por clientes
Informe #5: Informe de estadsticas de la base de datos de biblioteca
En este captulo agregaremos estos cinco informes al proyecto. Antes de escribir cualquier cdi-
go, necesitamos imaginar cmo vamos a obtener los datos. Debido a que stos provienen de la
base de datos Biblioteca, slo necesitamos generar la instruccin SQL para cada informe que se
vincular con el informe diseado.
El quinto informe, estadsticas, informar cosas como el nmero de artculos, el nmero de
clientes y valores estadsticos similares de la base de datos Biblioteca. Como estos datos en rea-
lidad no pueden venir de una sola instruccin SQL, extraeremos los datos de la base de datos y
generaremos un origen de datos personalizado que los alimente al informe.
Proyecto | 597
Si utiliza el diseador de consultas o construye la instruccin SQL a mano, con el tiempo saldr
con algo similar a lo siguiente, que usaremos dentro de la aplicacin Biblioteca:
/* ----- Informe #1: Informe de articulos prestados. */
SELECT PA.Apellido + ', ' + PA.Nombre AS NombreCliente,
PA.CodigoBarras AS CodigoBarrasCliente,
PC.FechaVencimiento, IC.CopiaNmero, IC.CodigoBarras AS CodigoBarrasArticulo,
NI.Title, CMT.NombreCompleto AS NombreMedio
FROM Cliente AS PA
INNER JOIN CopiaCliente AS PC ON PA.ID = PC.Cliente
INNER JOIN CopiaArticulo AS IC ON PC.CopiaArticulo = IC.ID
INNER JOIN ArticuloConNombre AS NI ON IC.IDArticulo = NI.ID
INNER JOIN CodigoTipoMedio AS CMT ON NI.TipoMedio = CMT.ID
WHERE PC.Regresado = 0
AND PC.Faltante = 0
AND IC.Faltante = 0
ORDER BY NI.Titulo, IC.CopiaNmero, PA.Apellido, PA.Nombre
Esta consulta vincula todas las tablas, y luego solicita cada registro que no se ha regresado (PC.
Regresado = 0). Ignora cualquier artculo marcado como faltante (PC.Faltante = 0 AND
IC.Faltante = 0). Esta consulta con el tiempo orienta el informe. Pero por ahora, tenga en
Los dos informes siguientes son para artculos vencidos y artculos faltantes. Para m, el es-
quema del informe #1 es exactamente lo que quiero ver en estos otros dos informes, as que slo
usemos la misma instruccin SQL. Todo lo que necesitamos hacer es cambiar la clusula WHERE.
Para el informe de artculos vencidos, use esta clusula WHERE:
WHERE PC.Regresado = 0
AND PC.Faltante = 0
AND IC.Faltante = 0
AND PC.FechaVencimiento < GETDATE()
El cuarto informe despliega el monto de multas que an deben los clientes, de modo que ne-
cesitar un esquema diferente. He aqu su instruccin SQL, que usa algunas caractersticas de
agrupacin agregados:
/* ----- Informe #4: Informe de multas adeudadas por clientes. */
SELECT PA.Apellido + ', ' + PA.Nombre AS NombreCliente,
PA.CodigoBarras AS CodigoBarrasCliente,
SUM(PC.Multa - PC.Pagado) AS MultasVencidas
FROM Cliente AS PA
INNER JOIN CopiaCliente AS PC ON PA.ID = PC.Cliente
GROUP BY PA.Apellido + ', ' + PA.Nombre, PA.CodigoBarras
HAVING SUM(PC.Multa - PC.Pagado) > 0
ORDER BY NombreCliente
Proyecto | 599
Para el informe final, slo usaremos un esquema con dos valores de cadena: un nombre esttico
y su valor relacionado. He aqu su esquema:
Class EsquemaInforme5
Public Property NombreEntrada As String
Public Property ValorEntrada As String
End Class
Acceso al proyecto
Cargue el proyecto Cap21 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap21 (Final) cdigo.
Una vez que las clases de esquema estn en el proyecto, necesitar generar el proyecto antes de
que esas clases puedan usarse en informes RDLC como orgenes de datos. En el proyecto Biblio-
teca, genere el proyecto ahora con el comando de men Generar Generar Biblioteca. Los tres
esquemas deben entonces aparecer como orgenes en el panel Orgenes de datos (vase la figura
21-15). Si el panel Orgenes de datos est cerrado, bralo usando el comando de men Datos
Mostrar orgenes de datos.
Adicin de informes
Como ya creamos juntos un informe RDLC al principio del captulo, segu adelante y agregu
los cinco informes integrados:
InformePrestados.rdlc
Este archivo implementa el informe #1, el informe artculos prestados. Usa el esquema
de clase EsquemaInformeArticulosCliente, e incluye tres columnas en los datos princi-
pales: nombre de cliente/cdigo de barras, nombre de artculo/cdigo de barras/detalles, y
fecha de vencimiento. Para el campo de nombre de artculo, quera presentar informacin
adicional cuando est disponible. El nombre del artculo, el nmero de copias y el tipo de
medios son valores obligatorios, pero el cdigo de barras de artculo es opcional. He aqu el
formato que deseaba:
Nombre articulo (#CopiaNumero, TipoMedio, CodigoBarras)
Proyecto | 601
Recuerde que los informes pueden usar diversos formatos de origen de datos, incluidas conexio-
nes de base de datos, matrices y colecciones. De informe #1 a #4 usarn una instancia System.
Data.DataTable y el informe #5 pasar una coleccin genrica Lista.
El mejor momento para desechar los datos es cuando se cierra el informe. Agregue el siguiente
manejador de eventos al formulario, que confirma que los datos dan soporte al proceso de dese-
cho antes de llamar al mtodo Dispose.
El cdigo que abre este formulario de despliegue pasar en los valores de informe esenciales me-
diante un mtodo pblico llamado IniciarInforme. Agregue su cdigo ahora.
Proyecto | 603
Este cdigo le indica al visor cul informe usar como un recurso incrustado y luego adjunta los
datos como un origen de datos personalizado. Local en estos nombres de propiedades indica un
informe local (cliente) en lugar de un informe de servidor que se ejecute dentro de SQL Server.
Cuando estbamos jugando antes con los informes, vimos que el modo de despliegue prede-
terminado era rellenar toda la pantalla con contenido de pgina. De manera personal, me
gusta ver estos lmites de pgina falsos. El control MicrosoftReportViewer no incluye una
propiedad que nos permita cambiar esta vista predeterminada (por qu no?), pero an podemos
ajustar el estilo de despliegue inicial mediante mtodos en el control. Cuando agregamos el visor
de informe al formulario, Visual Studio tambin agreg la siguiente instruccin al manejador de
eventos Load formulario:
InformeContenido.RefreshReport()
Ya antes agregamos soporte para nuestros cuatro informes integrados en este cdigo de formula-
rio. En un tributo a la interminable realidad de olvidos para finalizar todo el cdigo, necesitamos
agregar algn cdigo que subestimamos antes. Si utiliza un archivo de configuracin de informe
XML para rellenar la lista del informe, y proporciona una descripcin para cada informe en XML,
cada entrada despliega esa descripcin en la mitad inferior del formulario de seleccin de infor-
mes. Pero si no utiliza un archivo de configuracin, y slo depende del formulario para agregar los
cinco informes integrados como opcin predeterminada (que lo hace), el formulario no desplega-
r descripciones asociadas, porque olvidamos agregarlos. Agregue una funcin a la clase Selec-
cionarInforme que devuelve una descripcin corta para cada uno de los cinco informes.
Proyecto | 605
EntradaInforme.Descripcion = ObtenerDescripcionInformeIntegrado( _
EntradaInforme.TipoElemento)
Evidentemente, este cdigo no hace mucho. Cambie cada una de las lneas TODO, eliminando la
parte TODO: Escribir de la instruccin. De modo que la lnea que dice:
' TODO: Escribir InformeBasicoPrestado(
)
cambie el cdigo a:
InformeBasicoPrestado()
Proyecto | 607
ErrorHandler:
ErrorGeneral("SeleccionarInforme.InformeBasicoPrestado", _
Err.GetException())
Return
End Sub
El cdigo recupera los registros especficos del informe de la base de datos y se asegura de que
se incluy por lo menos un registro. (Pudimos agregar la instruccin SQL a la base de datos
Biblioteca como procedimiento almacenado o una vista y llamarlo, en cambio. Para los fines de
este tutorial, era ms simple almacenar la instruccin directamente en cdigo.) Luego llama al
visor del informe, pasando el nombre del archivo RDLC, el nombre del esquema (en el formato
NombreProyecto_NombreClase) y la tabla de datos.
A continuacin, agregue los mtodos informeBasicoVencido e InformeBasicoFaltante.
No mostrar el cdigo aqu porque, excepto por el nombre del archivo RDLC y la clusula WHE-
RE en la instruccin SQL, son idnticas a InformeBasicoPrestado.
Tambin es muy similar al mtodo InformeBasicoPrestado, pero usa la instruccin SQL que
diseamos antes para la recuperacin de multas del cliente. Tambin usa un esquema diferente
y un nombre de informe.
formularioInforme.IniciarInforme("Biblioteca.InformeMultasCliente.rdlc", _
"Biblioteca_EsquemaInformeMultasCliente", datosInforme)
' ----- Generar los datos del informe. Todo cuenta a partir de las
' diferentes tablas.
datosInforme = New Collections.Generic.List( _
Of EsquemaInformeEstadistica)
For contador = 1 To ContarSubCadena(conjuntosTablas, ",") + 1
Proyecto | 609
ErrorHandler:
ErrorGeneral("SeleccionarInforme.InformeBasicoEstadistica", _
Err.GetException())
Return
End Sub
Debido a que realmente necesitamos obtener la misma informacin (COUNT(*)) para cada una
de las seis tablas afectadas, acabo de implementar el cdigo como un bucle, y genere la instruc-
cin SQL para cada una a medida que recorremos el bucle. Un nombre de tabla amigable y la
cuenta de registros son almacenados entonces en la lista genrica, que se termina enviando al
informe.
Ahora puede ejecutar la aplicacin y usar los cinco informes integrados. Debe iniciar sesin
como bibliotecario o administrador, y luego acceder al panel Imprimir informes en el formulario
principal.
Aunque usted no lo crea, hemos terminado casi con la aplicacin. Lo nico importante que
queda por hacer es procesar los artculos vencidos de cliente para ver si se necesitan las multas.
Agregaremos este cdigo en el siguiente captulo, y tambin echaremos un vistazo a la asignacin
de licencias.
El licenciamiento de contenido .NET apropiado puede hacer la diferencia entre el dominio de mer-
cado y la bancarrota financiera. Y slo estoy hablando acerca de entender los acuerdos de licencia
incluidos con Visual Studio. Todava tiene que descubrir un mtodo apropiado para el licencia-
miento de su propia aplicacin antes de mandarla a sus clientes.
El licenciamiento y los acuerdos de licencia son medios esenciales para proteger la propiedad
intelectual que tanto trabajo le ha costado desarrollar. Cmo funciona el licenciamiento? La
clave se encuentra en la raz de la palabra: licencia viene de li- (decir una mentira) y -cence
(de centavos). Juntas, significan decir mentiras acerca de pequeas unidades monetarias. La
confusin creada al tratar de descubrir lo que esto significa mantiene a los malos perplejos y lo
suficientemente ocupados como para que no roben su aplicacin.
Si este mtodo no funciona, existen algunas soluciones, algunas de las cuales revisar en este
captulo. Parte del anlisis se enfoca en disear un sistema de licenciamiento que aparecer en el
proyecto Biblioteca. .NET Framework incluye clases de licenciamiento de componentes pero se
usan, sobre todo, para diseadores de controles usados por otros programadores dentro de Visual
Studio IDE, y no para aplicaciones de usuario. No cubriremos estas caractersticas de licencia-
miento en este captulo. Si tiene curiosidad acerca de esas caractersticas, empiece por leer acerca
de License Compiler (lc.exe) en la ayuda en lnea de Visual Studio.
611
Probablemente aqu?
Libertad Seguridad
Si va a la parte de Libertad del espectro (conveniente para los usuarios y hackers), tendr que
ir por la confiabilidad de los usuarios, y cualquier guardia armado que mande a sus oficinas,
para que se siga cumpliendo con el programa. En la parte de Seguridad de la escala (seguro
para los programadores y despachos de abogados con honorarios altos), el software imple-
menta prcticas y polticas que aseguran que slo los usuarios con licencia de la aplicacin lo
usen o lo instalen; no se necesitan guardias armados.
En el resto de esta seccin se analizan las posibles opiniones que puede seleccionar dentro del
rango Libertad-Seguridad.
Acceso controlado
El nivel ms alto de seguridad requiere una falta de confianza evidente del usuario, aunque pue-
de haber muy buenas razones para esto. En el caso de aplicaciones demasiado confidenciales, el
vendedor de software puede poner su producto a disposicin de un nmero limitado de clientes,
y despus slo en una base de arrendamiento. Como parte de este acuerdo de arrendamiento, el
cliente accede a tener un miembro de personal entrenado del vendedor de software en el sitio,
ejecutando y manteniendo la aplicacin para el cliente. Como mnimo, el vendedor requerir
que uno de sus empleados est disponible de manera inmediata al cliente cuando la aplicacin
se usa.
En un mundo de aplicaciones de software comerciales, parece inconcebible que ese sistema
pueda existir. Pero en situaciones de alto riesgo, las preocupaciones de seguridad se elevan a tal
Acuerdos de licencia
Un acuerdo de licencia es un documento en que la parte denominada primera parte a partir
de aqu presta amigablemente a la parte denominada segunda parte ciertos derechos, por una
remuneracin, bonos del tesoro y otros beneficios; a cambio, la denominada segunda parte
har lo mismo para la denominada primera parte sin respeto por ninguna otra parte, partida
o entera.
Intentemos eso de nuevo. Un acuerdo de licencia le dice a un usuario Contina, instala y usa
el software, pero tienes que seguir estas reglas. Aunque a menudo estn escritas en condiciones
legales, tambin pueden aparecer en un lenguaje real, como el espaol. Tambin tienen un rango
en derechos otorgados, que va desde Puede usar esto, pero cuando termine, debe destruir todas
las copias hasta selo, y sintase libre de pasar una copia del programa y su cdigo fuente a
sus amigos y conocidos.
El software Biblioteca proporcionado con este libro incluye un acuerdo de licencia. (Lo inclu
en el apndice B.) Cuando instal el cdigo de ejemplo, accedi a los trminos del acuerdo de
licencia, incluida la parte acerca de mantener bien a mi familia, financieramente en mis aos
de retiro. Pero ya es suficiente sobre m; hablemos acerca de los acuerdos de licencia que tal vez
quiera usar para sus aplicaciones.
Si est desarrollando un programa de catlogo de DVD para su primo Fernando, tal vez se
salte la parte del acuerdo de licencia. Pero cualquier software que haga en las instalaciones de
un trabajo para uso fuera de su propia compaa, debe incluir algn tipo de acuerdo entre
usted (o su compaa) y el usuario del software. Este acuerdo debe definirse como parte del
contrato que estableci el proyecto de desarrollo de software (esto es tpico para consulta de
software), o puede incluir el acuerdo como un componente del software (comn para progra-
mas comerciales).
Cualquiera que sea el mtodo que seleccione, es importante que lo ponga por escrito, porque
puede ahorrarle dolores en el camino. Una vez tuve un cliente que insisti que yo le pasara una
copia del cdigo fuente para una aplicacin que le escrib, para que pudieran mejorarlo y vender
la nueva versin a otro negocio (que descaro!). Por fortuna, tenamos un contrato escrito que
deca las reglas de compromiso. Tenan derecho a una copia del cdigo fuente para propsitos de
archivado, pero no podan usarlo o derivar productos de ste sin consentimiento mo por escrito.
Esto les dio un nivel de seguridad mientras todava proporcionaban los medios para que yo le
diera el mejor soporte posible para su organizacin. Por fortuna, todo lleg a una conclusin
feliz, y como ese cdigo de Visual Basic 3.0 ya no corre, es un punto debatible.
Ofuscacin
Alud un poco a las caractersticas de ofuscacin en Visual Studio 2008 en los captulos 1 y 5,
pero es buen momento para que echemos un vistazo a las caractersticas. Visual Studio incluye
una versin reducida de Dotfuscator, de una compaa llamada PreEmptive Solutions (no es
parte de Microsoft, todava). Para acceder al programa, use el comando de men Tools Dot
fuscator Community Edition en Visual Studio. La interfaz principal aparece en la figura 22-2.
textoResultado = Trim(textoOriginal)
If (Len(textoResultado) >= anchoTexto) Then
' ----- Truncar lo necesario.
Return Trim(Left(textoOriginal, anchoTexto))
Else
' ----- Empezar con espacios adicionales.
Return Space((anchoTexto - Len(textoOriginal)) \ 2) & _
textoResultado
End If
End Function
Este cdigo es muy sencillo de entender, sobre todo con los comentarios y el mtodo signifi-
cativo y los nombres de variables. Aunque la ofuscacin de .NET funciona en el nivel MSIL,
pretendamos que el ofuscador funcion directamente en el cdigo de Visual Basic. La ofuscacin
de este cdigo puede producir resultados similares al siguiente:
Public Function A(ByVal AA As String, _
ByVal AAA As Integer) As String
Dim AAAA As String
AAAA = Trim(AA)
If (Len(AAAA) >= AAA) Then
Return Trim(Left(AA, AAA))
Else
Return Space((AAA - Len(AA)) \ 2) & AAAA
End If
End Function
En una rutina tan simple, an podemos descubrir la lgica, pero con ms esfuerzo que en la
versin original. Naturalmente, la ofuscacin real va mucho ms all de esto, revolviendo la legi-
bilidad del cdigo en el nivel IL, y confundiendo a los lectores de cdigo y hackers.
Para ofuscar un ensamblado:
1. Genere su proyecto en Visual Studio usando el comando de men Generar Generar
[nombre de proyecto].
2. Inicie Dotfuscator al usar el comando de men Tools Dotfuscator Community Edition,
en Visual Studio.
Ofuscacin | 617
Cada vez que se ejecuta la aplicacin Biblioteca, intenta leer el archivo de licencia. Si no existe,
o si contiene datos o una firma no vlidos, el programa degrada las caractersticas disponibles,
deshabilitando las caractersticas para las que se considera que no tienen licencia.
Eso parece suficiente. El proceso que genera la firma digital tambin almacena una firma cifrada
dentro del contenido XML.
Resumen
Ya que a menudo pasar decenas o centenas de horas diseando y desarrollando una aplicacin
de Visual Basic con calidad, es importante usar el licenciamiento apropiado y la tecnologa de
Resumen | 621
Proyecto
En el cdigo de proyecto de este captulo seguiremos dos de los cuatro pasos de licenciamiento
analizados en la seccin El sistema de licenciamiento de biblioteca, en pginas anteriores de
este captulo: generar y usar el archivo de licencia. El diseo que creamos antes es suficientemente
bueno para nuestras necesidades, aunque todava necesitamos registrarlo en la documentacin
tcnica del proyecto. No instalaremos formalmente el archivo de licencia hasta que creemos el
programa de configuracin, en el captulo 25.
Archivo de licencia
El proyecto Biblioteca lee un archivo de licencia especfico de cliente generado por la apli-
cacin de soporte Library License Generation. Este programa genera un archivo de licencia
XML firmado digitalmente que incluye informacin de licencia. Aqu se muestra un ejem-
plo de contenido de archivo de licencia:
<?xml version="1.0"?>
<License>
<Product>Proyecto Biblioteca</Product>
<FechaLicencia>1/1/2000</FechaLicencia>
<FechaExpiracion>12/31/2999</FechaExpiracion>
<VersionCubierta>1.*</VersionCubierta>
<Licenciatario>Juan Q. Publico</Licenciatario>
<NumeroSerie>LIB-123456789</NumeroSerie>
<Signature>
Aqui aparece la firma digital (no mostrada)
</Signature>
</License>
Proyecto | 623
La firma digital ocurre por medio de la clase SignedXml (en el espacio de nombre System.
Security.Cryptography.Xml). Esta clase usa unos cuantos mtodos de firma diferentes. El
que seleccion (XmlDsigCanonicalizationUrl) se usa para XML tpico e ignora los comen-
tarios incrustados.
Proyecto | 625
Aqu se muestra un ejemplo de archivo de licencia XML que incluye una firma digital. sta es
la que he incluido en el directorio LicenseFiles en la instalacin de origen del libro (con algunas
lneas ajustadas para que quepan en esta pgina).
<?xml version="1.0"?>
<Licencia>
<Producto>Proyecto Biblioteca</Producto>
<FechaLicencia>11/30/2009</FechaLicencia>
<FechaExpiracion>12/31/2999</FechaExpiracion>
<VersionCubierta>1.*</VersionCubierta>
<Licenciatario>Juan Q. Publico</Licenciatario>
<NumeroSerie>LIB 123456789</NumeroSerie>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm=
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm=
"http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/
xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/
xmldsig#sha1" />
<DigestValue>CezlqVmSO97b/0rwtQi2c31mqaE=
</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>s+B3s392uePWsbGX4Jpl1p3A/AwSIJtsI
Hq79sgsinUx280358x8mNgwRx/vytlitdRaCgX7aqMD4xz
gvKxejsgqhZ0/cQRu6zY6T9rLYSkcVyuvt5RtleT6rNwz/
6TnHI7KEqemBJM3eDErdzWhVfgrsNjfDZvc2Piav3ddSdI=
</SignatureValue>
</Signature>
</Licencia>
Acceso al proyecto
Cargue el proyecto Cap22 (Antes) cdigo mediante las plantillas de Nuevo proyecto o
accediendo directamente al proyecto desde el directorio de instalacin. Para ver el cdigo
en su forma final, cargue, en cambio, Cap22 (Final) cdigo.
El programa ajustar su comportamiento dependiendo de si est licenciado o no. Pero para ha-
cer tal determinacin, necesita asegurarse de que el contenido del archivo de licenciamiento es
vlido y no ha sido saboteado. Para hacer esto, necesita una forma de volver a ordenar la firma
y compararla con el resto de la licencia para asegurarse de que coincide. Generamos la firma al
usar la clave privada; debemos volverla a ordenar mediante la clave pblica.
Podemos almacenar la clave pblica en su propio archivo fuera del programa, pero entonces tal
vez se pierda (al igual que mis claves reales). En vez de eso, almacenaremos la clave pblica como
un recurso de aplicacin, encontrada de manera externa en el cdigo fuente de la carpeta Recur-
sos. Ya he agregado el recurso a su copia del programa, y la he denominado ClavePublicaLi-
cencia. Con esta clave incrustada en la aplicacin, cualquier regeneracin de las claves pblica o
privada requerir modificacin de su recurso. En el cdigo, nos referimos al contenido XML de la
clave pblica al usar su nombre de recurso:
My.Resources.ClavePublicaLicencia
Proyecto | 627
Imports System.Xml
Imports System.Security.Cryptography.Xml
Usaremos una enumeracin para indicar el estado de la licencia. Agrguelo ahora al mdulo
General.
Tambin agreguemos una estructura simple que comunique los valores extrados del archivo de
licencia. Agregue este cdigo al mdulo.
Todo lo que necesitamos ahora es algo de cdigo para llenar en la estructura ArchivoLicen-
ciaPredeterminado. Agregue la funcin ExaminarLicencia al mdulo General.
Proyecto | 629
Es mucho cdigo, pero la mayor parte slo carga y extrae valores del archivo de licencia XML.
La parte de revisin de firma es relativamente corta.
clavePublica = RSA.Create()
clavePublica.FromXmlString(My.Resources.LicenciaClavePublica)
documentoFirmado = New SignedXml(ContenidoLicencia)
nodosCoincidentes = ContenidoLicencia.GetElementsByTagName( _
"Firma")
documentoFirmado.LoadXml(CType(nodosCoincidentes(0), XmlElement))
If (documentoFirmado.FirmaRevisada(clavePublica) = False) Then
' ----- No valido
End If
Proyecto | 631
En la figura 22-8 se muestra el formulario AcercaDe en uso con detalles desplegados desde el
archivo de licencia.
Slo por diversin, cambie el nmero de versin en mi archivo de licencia de 1.* a 2.* sin
actualizar la firma digital. Seguramente, cuando despliegue el formulario AcercaDe nuevamen-
te, desplegar Sin licencia, porque la revisin de la firma fall. Cmo prob el cdigo tan
temprano? Copi el archivo LicenciaBiblioteca.lic del subdirectorio ArchivosLicencia instalado
del libro y coloqu esa copia en el subdirectorio bin\Debug del cdigo fuente del proyecto. Ms
adelante podr colocar el archivo en cualquier lugar que quiera y explorarlo, pero estamos ade-
lantndonos.
Imposicin de la licencia
En algn momento, una licencia faltante o no vlida debe tener un impacto negativo en el uso
de la aplicacin. Cuando eso pasa, debemos darle al usuario una oportunidad de corregir el
problema al localizar un archivo de licencia vlido. Haremos esto a travs del nuevo formulario
LocalizarLicencia.vb. Ya he agregado ese formulario a su proyecto. Aparece en la figura 22-9.
Este formulario inicia con una llamada a su funcin CambiarLicencia, que regresa True si el
usuario cambia la licencia. Casi todo este cdigo de formulario administra el despliegue, presen-
tando razones detalladas de por qu la licencia es vlida o no al usar los resultados de la funcin
ExaminarLicencia. Si por cualquier razn la licencia no es vlida, un clic en el botn Localizar
permite al usuario explorar una versin mejor.
Private Sub ProgramaAcercaDe_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
' ----- Actualiza el numero de version.
Proyecto | 633
Justo antes de este bloque de cdigo, agregue el siguiente cdigo de revisin de licencia.
Proyecto | 635
' ----- Las multas estan vencidas en este registro. Idear cuanto.
DiasDeMulta = CInt(DateDiff(DateInterval.Day, _
CDate(infoBD!FechaVencimiento), hastaFecha) - _
DateDiff(DateInterval.Day, CDate(infoBD!FechaVencimiento), _
ultimoProceso) - FineGraceDays)
If (DiasDeMulta < 0) Then DiasDeMulta = 0
multasHastaAhora = 0@
If (IsDBNull(infoBD!Multa) = False) Then _
multasHastaAhora = CDec(infoBD!Multa)
multasHastaAhora += CDec(infoBD!MultaDiaria) * CDec(DiasDeMulta)
infoBD.Close()
infoBD = Nothing
ErrorHandler:
GeneralError("ProcesamientoDiarioPorCopiaCliente", Err.GetException( ))
Resume Next
End Sub
El estado sin pagar de un elemento tambin debe actualizarse justo antes de que se revise. Abra el
cdigo fuente del formulario FormularioPrincipal y ubique el manejador de eventos AccEn-
trada_Click. Cerca de la mitad del camino a travs de este cdigo, encontrar un comentario que
inicia con Manejar artculos faltantes. Justo antes de tal comentario, inserte el siguiente cdigo.
La revisin tiene que actualizar las multas del cliente tambin, justo antes de permitir que el
cliente sepa si hay, en realidad, alguna multa vencida. Muvase al manejador de eventos Formu-
larioPrincipal.AccClienteSalida_Click y agregue las siguientes instrucciones en la parte
superior de la rutina.
Proyecto | 637
Actualmente, el panel no hace mucho, as que cambiemos eso. La primera tarea es actualizar la
etiqueta de estado que aparece en la parte superior del panel. Agregue un nuevo mtodo deno-
minado ActualizarUbicacionProceso a la clase FormularioPrincipal del formulario.
ErrorHandler:
GeneralError("FormularioPrincipal.TareaProceso", Err.GetException(
))
Resume Next
Proyecto | 639
El procesamiento diario ocurre cuando el usuario hace clic en el botn Procesar. Agregue el
siguiente cdigo al manejador de eventos AccProcesar_Click.
' ----- Obtener la lista de todos los articulos que probablemente necesiten procesamiento.
textoSql = "SELECT PC.ID FROM CopiaCliente AS PC " & _
"INNER JOIN CopiarArticulo AS IC ON PC.CopiaArticulo = IC.ID "& _
"WHERE PC.Regresado = 0 AND PC.Faltante = 0 " & _
"AND IC.Faltante = 0 AND PC.FechaVencimiento < " & FechaBD(Today) & _
" AND (PC.FechaProceso IS NULL OR PC.FechaProceso < " & _
FechaBD(Today) & ")"
If (ProcesarUbicacion.SelectedIndex <> -1) Then
idUbicacion = CInt(CType(ProcesarUbicacion.SelectedItem, _
DatosListaElementos))
If (idUbicacion <> -1) Then textoSql &= _
" AND IC.Location = " & idUbicacion
Else
idUbicacion = -1
End If
tablaBD = CrearTablaDatos(textoSql)
For Each filaBD In tablaBD.Rows
ProcesamientoDiarioPorCopiaCliente(CInt(filaBD!ID), Today)
Next filaBD
tablaBD.Dispose()
tablaBD = Nothing
Me.Cursor = Cursors.Default
ErrorHandler:
GeneralError("FormularioPrincipal.AccProcesar_Click", Err.GetException(
))
Resume Next
Pruebe el cdigo, ejectelo, localice un archivo de licencia vlido y pruebe las diferentes carac-
tersticas administrativas.
Esto marca el final de la colocacin de cdigo principal en el proyecto Biblioteca. Felicidades!
Pero todava hay algo mucho que hacer, como puede ver por la presencia de cuatro captulos
ms. Ahora no sera el momento de cerrar el libro y dar por terminado el da. Pero sera un buen
momento para aprender acerca de ASP.NET, el tema del siguiente captulo.
Proyecto | 641
Cuando sir Tim Berners-Lee (recibi el ttulo de caballero en 2004) invent World Wide Web
en 1989, realmente no era muy importante. Como el diseador principal de HTTP y HTML,
ciertamente no fue perezoso. Pero la mayor parte de las tecnologas para estructuracin y trans-
porte de pginas Web exista desde aos antes, incluso dcadas. SGML (la base de HTML) y
los sistemas de hipervinculacin han existido desde la dcada de 1960, y la transmisin de datos
basada en Internet entre clientes y servidores ya era comn entre campus de universidades y
algunos negocios. An as, aqu estamos en el siglo xxi, y World Wide Web es el centro de tanta
tecnologa computacional que hace que mi cabeza gire. Gracias, Sr. B-L.
Microsoft promueve .NET como el sistema para desarrollar pginas Web y software relacionado.
Y realmente es un buen sistema. Conforme nos adentremos en el cdigo, descubrir que cerca
de 90% de lo que hace para escribir aplicaciones Web en Visual Studio es idntico a lo que hace
cuando escribe aplicaciones de escritorio. Es fcil de hacer, y muy divertido, as que tal vez querr
escribir algunos programas. Y eso es lo que haremos en este captulo. Pero primero, revisemos
brevemente lo que pasa en el mundo de la comunicacin de World Wide Web.
642
Esto ejecuta el programa Telnet, un programa de emulacin de terminal que permite conectarse
a sistemas remotos a travs de una interfaz de texto. (Telnet est instalado en Windows XP como
opcin predeterminada, pero es opcional en Windows Vista. Puede agregarlo a Windows Vista
mediante la applet Programas y caractersticas del Panel de control.) Telnet suele conectarse al
puerto 23 TCP/IP, pero puede especificarse el puerto que desee, como lo hicimos aqu con el
puerto WWW predeterminado de 80.
Es posible que su pantalla se quede en blanco, o que se quede as, como si estuviera muerta. Si
tiene suerte, ver un mensaje connected, pero tal vez no. Y est bien. Su sistema est conectado
al servidor Web de Google. Escriba el siguiente comando:
GET / HTTP/1.0
No olvide los espacios que rodean la primera diagonal. Despus de este comando oprima dos
veces la tecla Enter. Este comando pide al sistema remoto enviar la pgina Web predeterminada
en la parte superior de la jerarqua Web del servidor. Y porque lo pidi, lo har.
HTTP/1.0 200 OK
Cache-Control: private
Content-Type: text/html; charset=ISO-8859-1
Set-Cookie: PREF=ID=1c1dd342e463f3f1:TM=1199325226
:LM=1199325226:S=Pl-4f1fg4yh8Mvw7;
expires=Sat, 02-Jan-2010 01:53:46 GMT;
path=/; domain=.google.com
Server: gws
Date: Tue, 01 Jan 2008 01:30:00 GMT
Connection: Close
<html><head>
...resto del contenido de la pagina Web HTML aqui...
</body></html>
Programacin de Internet
Las pginas estticas estuvieron bien por un tiempo, pero despus Internet se volvi montono.
Finalmente, alguien tuvo una brillante idea: Tenemos un programa en ejecucin en nuestro
servidor Web que est respondiendo a clientes, y alimentndolo de pginas pedidas. Qu pasa-
ra si pudiramos mejorarlo para que, en ciertas pginas, llamara a un programa o una secuencia
de comandos que generara el contenido HTML al vuelo y enviara de regreso el contenido al
cliente? Entonces cambiaron el proceso de servidor. Ahora, cuando el cliente peda una pgina
Web que terminaba con una extensin .cgi, el proceso de servidor Web ejecutaba la secuencia de
comandos que generaba el contenido. El sistema tambin proporcionaba los medios para con-
tenido proporcionado por el cliente para abrirse paso hasta la secuencia de comandos, haciendo
posible la personalizacin de caractersticas.
De ah, el paso era corto a la obtencin de una solucin genrica. En la plataforma de Microsoft,
el servicio de informacin de Internet (IIS, Internet Information Server) dio soporte a comple-
mentos a los que poda llamarse con base en la extensin del archivo solicitado. Esto llev, a las
pginas activas de servidor (ASP, Active Server Pages), una solucin que permiti a los desarro-
lladores incrustar secuencias de comandos del lado del servidor (a menudo utilizando VBScript,
una variacin de Visual Basic) en el contenido HTML, y que haca que ajustara el contenido
antes de enviarse al cliente.
Alguien ms dijo: Si podemos escribir secuencia de comandos en el lado del servidor, no po-
dramos tambin incluir una secuencia de comandos del lado del cliente justo en el contenido
HTML que un explorador Web inteligente pudiera procesar? Al poco tiempo, los desarrolladores
del lado del cliente y servidor estaban combatiendo en las calles, pero la batalla no lleg muy lejos,
porque todos los programadores estaban cansados. La causa? Programar en secuencia de coman-
dos! Ya sea incrustar secuencias de comandos en HTML (el lado del cliente) o generar HTML
desde una secuencia de comandos (el lado del servidor), la programacin de secuencia de coman-
dos es difcil, lenta, alta en colesterol malo y casi imposible de depurar interactivamente.
Algunos programadores de secuencias de comandos Web no haban usado un compilador de
lenguaje por aos, y estaban al borde del colapso debido a comas fatales inducidos por secuencia
de comandos. Se poda compilar lgica del lado del servidor en una DLL y usarlo para procesar
pginas Web, pero estaba lejos de ser sencillo, y estas DLL todava estaban a menudo vinculadas
en el contenido HTML por medio de secuencias de comandos cortas.
Despus lleg .NET y su soporte para desarrollo de aplicacin compilada del lado de servidor.
Los programadores de secuencias de comandos lanzaron un suspiro colectivo de alivio desde
sus camas de hospital; ahora podan usar el poder completo de los lenguajes Visual Studio y
.NET para generar contenido HTML. Y este nuevo sistema, ASP.NET, fue diseado para que se
Caractersticas de ASP.NET
ASP.NET incluye muchos nuevos avances en tecnologa de desarrollo Web. Aqu se muestran
algunos de los ms famosos:
Cdigo compilado
Todo el cdigo que escriba para aplicaciones ASP.NET est totalmente compilado en ensam-
blados estndar DLL de .NET. Cuando el cliente pide un archivo con extensin .aspx, Internet
Information Server ubica este archivo (que contiene HTML o una combinacin de HTML/
ASP.NET) y la DLL compilada asociada, y los usa juntos para procesar el contenido de la p-
gina. Puede precompilar la DLL antes del despliegue, o permitir que ASP.NET lo compile al
vuelo la primera vez que se llama al archivo .aspx (aunque esto afecta un poco el rendimiento).
Soporte .NET
Las aplicaciones ASP.NET pueden acceder a .NET Framework Class Libraries (FCL, bi-
bliotecas de clase de .NET Framework) completas, excepto las que tienen como objetivo
especfico el desarrollo de escritorio. Cualquiera de las caractersticas y clases grandiosas que
tiene en aplicaciones .NET de escritorio estn en las aplicaciones Web tambin.
Basado en objeto
Las etiquetas HTML, como <textarea>, slo son en realidad cadenas de texto dentro de
un archivo de texto HTML ms grande. La creacin de secuencias de comandos del lado
de servidor antes de .NET fue un ejercicio de unin de cadenas, generando un archivo ms
grande de cadenas de contenido ms pequeas. ASP.NET trata a todos los elementos de
pgina Web como objetos verdaderos, junto con propiedades y eventos. Algunos de estos
objetos implementan controles complejos del lado del cliente, respaldados por cientos de
lneas de secuencia de comandos del lado del cliente que obtiene de manera gratuita.
Simplicidad de implementacin
Administrar secuencias de comandos del lado del servidor y personalizar DLL antes de
.NET no era muy divertido. Ciertos tipos de cabios requeran que se apagara por completo
Internet Information Server, o al menos que se deshiciera de la porcin que controlaba la
aplicacin que cambiaba. ASP.NET le permite hacer cambios en un sistema de produccin,
sin impactar a los usuarios activos. Si reemplaza una DLL compilada, ASP.NET empezar a
usarlo de inmediato, pero todava mantendr la versin antigua hasta que todos los clientes
existentes se hayan desconectado de sta.
Prueba de ASP.NET
Generemos una aplicacin ASP.NET muy simple, y examinmosla y examinemos sus partes para
descubrir de qu se trata.
Si est usando Visual Basic 2008 Express Edition, no podr seguir por com-
pleto estas instrucciones directamente porque ese producto no incluye ninguna
caracterstica ASP.NET o de desarrollo Web. En cambio, necesita descargar Vi-
sual Web Developer 2008 Express Edition del sitio Web de Microsoft MSDN
(http://msdn.microsoft.com/express). Su interfaz de usuario, aunque est muy
simplificada, ofrece mucha de la misma funcionalidad que el producto com-
pleto de Visual Studio. El tuturial incluido aqu fue escrito con Visual Studio
2008 Professional Edition.
Inicie Visual Studio y seleccione el comando de men Archivo Nuevo sitio Web. Aparece el
formulario Nuevo sitio Web (vase la figura 23-1). A diferencia de las aplicaciones de escritorio,
debe indicar de inmediato a Visual Studio dnde almacenar los archivos. Seleccionaremos una
ubicacin en el sistema de archivos local, pero este formulario tambin le permite trabajar en
un sitio Web remoto por medio de FTP o HTTP. Seleccione la plantilla Sitio Web ASP.NET,
inserte una ruta de directorio donde quiera almacenar los archivos y haga clic en el botn OK.
En la figura 23-2 se muestra Visual Studio listo para iniciar su nueva aplicacin Web (las barras
de herramientas desplegadas corresponden a mis preferencias).
El panel Explorador de soluciones ya muestra tres archivos y una carpeta incluida en el proyecto.
Si explora el directorio del proyecto (la ubicacin predeterminada en Windows Vista es C:\Users\
nombreusuario\Documents\Visual Studio 2008\WebSites\WebSite1) ver los mismos archivos. El
archivo web.config es un archivo XML que contiene configuraciones especficas de aplicacin;
est relacionado con el archivo app.config utilizado en aplicaciones de escritorio. Default.aspx es
la pgina Web, que contendr una mezcla de etiquetas y directivas HTML y ASP.NET especia-
les. El archivo Default.aspx.vb relacionado contiene el cdigo fuente tras el cdigo de Visual
Basic que en algn momento se compilar en un DLL.
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Pgina sin ttulo</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
Bueno, casi todo es HTML. Hay una lnea en la parte superior que inicia con <%@ que no se ve
como HTML real (y no lo es). sta es una directiva de pgina ASP.NET. Incluye propiedades que
ayudan a guiar a ASP.NET en el procesamiento de la pgina. Tomando prestado un estndar de
su predecesor ASP, ASP.NET usa el par de parntesis angulares <%...%> para marcar comandos
y cdigo especfico de ASP.NET. (Tambin es posible que reconozca estos marcadores del cap-
tulo 13, porque se usan en literales XML.)
Ya basta de HTML. Quin quera verlo de todas formas? Haga clic en el botn de seccin Di-
seo, o use el comando de men Ver Diseador para regresar a la pgina en blanco.
Creemos una aplicacin que multiplique dos nmeros proporcionados por el usuario y desplie-
gue el resultado. Para esta caracterstica simple, podemos escribir algo de JavaScript e incluirlo
como una secuencia de comandos del lado del cliente, pero estamos tratando de evitar hacer
cosas como sas. Escriba lo siguiente en la pgina Web:
Para multiplicar dos valores, ingrselos en los
campos de texto y haga clic en el botn Multiplicar.
Hice que Multiplicar apareciera en negritas al usar la secuencia de teclas Ctrl-B, como lo hara
en un procesador de palabras. Oprima Enter una vez. Como opcin predeterminada, la pgina
Web coloca todos los elementos como un documento de procesamiento de palabras, un mtodo
denominado modo de diseo de flujo. Tambin puede usar posicionamiento absoluto de elementos
individuales para colocarlos en una ubicacin especfica de la pgina.
Existe otra forma de organizar elementos en la pgina: a travs de una tabla HTML. Agreguemos
una ahora. Use el men de comando Tabla Insertar tabla. Cuando aparezca el cuadro de dilo-
go Insertar tabla, especifique una tabla personalizada que sea de tres filas y dos columnas. Despus
haga clic en Aceptar. La tabla debe aparecer inmediatamente en el cuerpo de la pgina Web.
No hay mucho que ver, pero se pondr mejor. Hasta ahora, no hemos hecho mucho ms de lo
que podramos hacer en el Bloc de notas. Pero ahora estamos listos para agregar algunos con-
troles. Si abre el cuadro de herramientas, ver controles muy parecidos a los que se encuentran
en una aplicacin Windows Forms (vase la figura 23-4).
Regrese brevemente al marcado HTML para esta pgina al hacer clic en el botn de seccin
Cdigo, en la parte inferior de la pgina. Si est familiarizado con HTML, puede observar la
etiqueta <table> de la tabla que agregamos. Pero tambin encontrar algo poco familiar dentro
de la primera fila de la tabla.
<table class="style1">
<tr>
<td>
Operand 1:
</td>
<td>
<asp:TextBox ID="PrimerOperando"
runat="server"></asp:TextBox>
</td>
</tr>
Es esa etiqueta </asp:TextBox>. Se parece un poco a otras etiquetas HTML, pero no hay eti-
quetas HTML que inicien con asp. sta es una etiqueta ASP.NET especial que representa una
clase de control Web Forms. Estos controles, y los atributos runat="server" que se distribuyen
a travs del marcado, son lo que hace que las pginas ASP.NET sean lo que son. Conforme ASP.
NET procesa la pgina .aspx, quita estas etiquetas de control personalizadas y llama a los contro-
les relacionados para generar su propio explorador neutral HTML.
End Sub
End Class
La meta de diseo de ASP.NET fue tener cdigo que fuera lo ms cercano posible al cdigo de la
aplicacin de escritorio, y as es. Agregue la siguiente lgica al manejador de eventos:
' ----- Multiplicar los dos numeros.
Producto.Text = Val(PrimerOperando.Text) * _
Val(SegundoOperando.Text)
If (Val(Producto.Text) < 0) Then
Producto.ForeColor = Drawing.Color.Red
Else
Producto.ForeColor = Drawing.Color.Black
End If
A medida que escriba, observ todo el IntelliSense respondiendo a cada teclazo que daba? No
poda indicar que fuera una aplicacin basada en Web, y eso es grandioso.
Oprima la tecla F5 para iniciar la aplicacin. Se le pedir que active la depuracin, que es lo
que quiere hacer. Esto modificar el archivo web.config de la aplicacin para dar soporte a de-
puracin. Ms adelante, querr deshabilitar esa caracterstica para que sus usuarios no puedan
depurar la aplicacin. Si abre el archivo web.config, ver esta lnea:
<compilation debug="true" strict="false" explicit="true"/>
Figura 23-7. Guau!, una aplicacin Web completa en menos de 10 lneas de cdigo.
Si no le gusta cmo se expande la tabla por la pgina, puede ajustarla con el panel CSS Proper-
ties. De regreso a Visual Studio, seleccione el comando de men Ver Propiedades de CSS. El
panel se abre y se ajusta a s mismo dependiendo del elemento de pgina que tenga seleccionado.
Para eliminar el romance de la tabla con el borde derecho, seleccione la tabla, desplcese a la
propiedad ubicacin/width y elimine el valor 100% de esa entrada de propiedad.
Ms acerca de eventos
Hasta ahora, nuestra aplicacin se ve como una de escritorio; el formulario despliega nuestras
configuraciones iniciales de arrastrar y colocar y de propiedades, y responde a un clic de botn al
regresar a la computadora de procesamiento para la lgica. Pero seamos honestos. No hay forma
de que una aplicacin Web alguna vez pueda responder a la misma cantidad de eventos que una
aplicacin de escritorio. Qu pasa cuando la conexin de Internet falla o est muy lenta? Cmo
maneja cosas como eventos TextChanged en campos de texto? No puede hacer que la pgina
Web regrese a la pgina de servidor cada vez que el usuario oprime una tecla.
El control TextBox ASP.NET tiene un evento TextChanged, pero no se activa para cada tecla-
zo. En realidad, no se activa nunca (como opcin predeterminada) hasta que algo (como un clic
de botn) causa que la pgina regrese al servidor. Y ah existen muchos otros eventos de control
que funcionan de esta forma. Todos estn guardados hasta que el usuario hace algo para traer
toda la pgina al servidor Web para procesamiento. En ese momento, estos eventos retrasados
finalmente se encienden, y el procesamiento contina como es normal.
Ahora la etiqueta Producto desplegar Sin datos la primera vez que aparece la pgina. Lo
importante del evento Load es que se ejecuta cada vez que la pgina Web se despliega. Debido a
que esta aplicacin de prueba sigue usando la misma pgina una y otra vez para sus resultados,
el manejador de eventos Load se ejecutar de nuevo cada vez. Este programa de prueba no es
realmente importante; el cdigo en el manejador de eventos AccMultiplicar_Click pasa por
alto su valor inicial Sin datos. Pero en otras aplicaciones tal vez no quiera seguir reinicializando
los datos. Por fortuna, el evento Load le permitir saber si sta es la primera vez que se ejecuta
mediante un miembro de nivel de pgina llamado IsPostBack.
' ----- Initializar los datos, pero solo la primera vez.
If (Me.IsPostBack = False) Then Producto.Text = "Sin datos"
Eso es View State. No me pregunte cmo funciona; no se lo dir (porque no lo s). Pero no es
importante saberlo. Slo es importante que ASP.NET sepa cmo funciona para que pueda man-
tener su aplicacin en funcionamiento como el sistema Windows Forms no lo hace.
Conforme agregue controles a su pgina, aumentar el tamao de View State. Debido a que
todo el contenido de pginas Web debe transportarse varias veces por Internet, un View State
ms grande lleva a tiempos de transmisin ms largos. Es posible desactivar View State para
controles especficos mediante la propiedad EnableViewState. Si no necesita que el valor de
un control se retenga tras cada uso de una pgina, es una buena idea desactivarlo.
Validacin de datos
Debido a que este cdigo de ejemplo usa la funcin Val de Visual Basic para preprocesar los
datos proporcionados por el usuario, casi siempre funciona sin error. Cualquier dato considera-
do invlido simplemente se convierte en cero. Otra opcin sera castigar al usuario por insertar
datos que no son vlidos antes de que el procesamiento ocurra, para validar los valores propor-
cionados. Los cinco validadores en la seccin Validation del cuadro de herramientas de Web
Forms le ayudan a hacer eso:
RequiredFieldValidator confirma que el usuario proporcione cualquier valor en un
control.
RangeValidator se queja si el valor de un control no cae entre dos valores.
RegularExpressionValidator le permite comparar el valor de un control contra un pa-
trn de expresin regular. Por ejemplo, puede comparar la entrada del usuario de un nmero
de serie con un patrn, para asegurarse de que incluya dos letras seguidas de cinco dgitos.
Eso debe verse familiar. Cree un nuevo sitio Web ASP.NET en Visual Studio. Escriba la siguiente
lnea en la parte superior de la pgina de contenido:
Biblioteca ACME Artculos prestados
Sintase libre de embellecerlo para que se vea mejor. Yo agregu las etiquetas <h1> alrededor
en el marcado para que se destaque. Debajo de esa lnea de ttulo, agregue un nuevo control
GridView a la pgina. Yo lo encontr en la seccin Datos de mi cuadro de herramientas de Vi-
sual Studio. La etiqueta inteligente del control se abre y muestra un panel Tareas de GridView,
como se muestra en la figura 23-9.
Muchas tecnologas intervienen para hacer WCF posible, pero no necesita conocerlas. En cam-
bio, implementar uno o ms mtodos de Visual Basic basados en una interfaz que usted defina.
Esta interfaz, marcada con atributos especficos de WCF, establece el contrato de servicio que
hace posible la comunicacin funcional entre dos sistemas.
Los servicios WCF aparecen como archivos .svc en su sitio Web. En Visual Studio puede crear
un nuevo sitio Web y seleccionar WCF Service como tipo de proyecto, o agregar un elemento
WCF Service a un proyecto de sitio Web existente. Cuando lo hace, Visual Studio agrega los
archivos necesarios a su proyecto. El primero es el archivo real .svc. Es una interfaz inteligente
conducida entre el sitio Web y el cdigo de servicio Web real. Aqu est lo que he encontrado
en mi archivo Service.svc:
<%@ ServiceHost Language="VB" Debug="true" Service="Service"
CodeBehind="/App_Code/Service.vb" %>
Esto se ve como cdigo de ejemplo para m, y lo reemplazar cuando escriba su propio servicio.
La clase Service en el cdigo implementa los miembros de la interfaz IService, encontrados
en el archivo relacionado IService.vb.
<ServiceContract()> _
Public Interface IService
<OperationContract()> _
Function GetData(ByVal value As Integer) As String
End Interface
Como se mostr, esta interfaz tambin contiene un miembro sin importancia de ejemplo, Get-
Data, que debe reemplazarse. Est marcado con el atributo enfocado en WCF <OperationCon-
tract> que, junto con el atributo <ServiceContract> de la interfaz, declara: Hay servicios
de WCF aqu. Recuerde que un atributo agrega metadatos a un ensamblado para que el compi-
lador u otro programa hagan algo especial con los elementos marcados. En este caso, el atributo
<OperationContract> le indica a WCF que trate el mtodo GetData (cuando se implementa)
como un miembro de servicio. WCF responde al conectar toda la plomera de cdigo que hace
el servicio posible.
Voy a reemplazar la funcin GetData con otra que al menos pretenda hacer algn trabajo real.
Primero, cambiar la interfaz IService para que defina el contrato.
<ServiceContract()> _
Public Interface IService
<OperationContract()> _
Function NumeroATexto(ByVal numeroOrigen _
As Integer) As String
End Interface
Si ejecuta esta aplicacin en Visual Studio, su explorador Web se abrir con la pgina (parcial)
que se muestra en la figura 23-10.
Los servicios WCF son mtodos, y un explorador Web no es un medio tpico prctico para
ejecutar subrutinas y funciones, as que aparece, en cambio, la pgina de la figura 23-10. Su
contenido informativo le muestra cmo puede probar o usar el servicio, ya sea a travs de una
utilera diseada para ese fin, o a travs de cdigo Visual Basic o C#.
Ya que tengo este servicio en ejecucin en mi sistema al usar mi servidor Web de prueba ASP.NET,
escribir una aplicacin de escritorio para llamar al mtodo NumeroATexto. Iniciar una instancia
separada de Visual Studio y crear un nuevo proyecto Windows Forms. Seleccione el comando de
men Proyecto Agregar referencia de servicio. Aparece el formulario Agregar referencia de servi-
cio; se trata de una herramienta que se usa para ubicar servicios WCF locales y remotos.
Puede pedir especficamente el servicio si sabe su direccin. Para determinar esto, haga doble
clic en el cono ASP.NET Development Web Server en la bandeja del sistema. El campo Root
URL proporcionar la base de la direccin. En mi sistema en este momento particular dice
http://localhost:49210/WebSite2, aunque, como predeterminada, cambiar nmeros de puer-
to si reinicio el servicio. Agregue esto al nombre del archivo .svc para su servicio.
http://localhost:49210/WCFService1/Service.svc
Para probar nuestro servicio, agregu un control TextBox y uno Button a Form1, y agregu el si-
guiente cdigo (us el nombre de espacio de servicio predeterminado de ServiceReference1):
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
MsgBox((New ServiceReference1.ServiceClient). _
NumeroATexto(CInt(Val(TextBox1.Text))))
End Sub
Ejecute el programa, escriba un nmero del 0 al 9 y despus haga clic en el botn para llamar
correctamente al servicio Web y obtener la versin en espaol del nmero. Y hubiera funciona-
do bien igualmente si el servicio NumeroATexto se ejecutara en un servidor Web en una de las
instalaciones de investigacin en el Polo sur.
Proyecto
Para el proyecto de este captulo gener un sitio Web simple de varias pginas que 1) permite
al usuario buscar elementos en la base de datos Biblioteca y 2) duplica el informe Estadstica
de biblioteca creado en el captulo 21, pero sin el componente RDLC. Fui ms all e inclu un
proyecto completado en su directorio de cdigo fuente instalado, en el subdirectorio SitioWeb-
Biblioteca. Puede abrirlo al ubicar su directorio con el comando de men Archivo Abrir sitio
Web en Visual Studio.
Como se muestra en la figura 23-12, el proyecto incluye 11 archivos y dos subdirectorios.
Proyecto | 663
BDBiblioteca.Close()
La pgina predeterminada
La pgina Default.aspx es el punto de inicio para la aplicacin Web Biblioteca y aparece en la
figura 23-13.
Proyecto | 665
Resultados de bsqueda
La pgina ResultadosBusqueda.aspx despliega cualquier resultado coincidente de la seccin de bs-
queda de elemento Default.aspx. Como se muestra en la figura 23-14, incluye un control GridView
para la lista de resultados, adems de un control Label que muestra un conteo de coincidencias.
En la figura 23-15 se muestran las propiedades para la primera columna de datos unida, "Nom-
bre de artculo. Est unida a un campo en los datos denominado DatosArticulo por medio
de la propiedad DataField. Las siguientes dos columnas se configuran de manera similar pero
usan los datos entrantes NombreAutor y TipoMedio. La cuarta columna proporciona un hi-
pervnculo a DetalleBusqueda.aspx para cada registro coincidente. Para generar esta columna, la
agregu como una columna HyperLinkField en lugar de una BoundField. Ingrese Detalle
en su propiedad Text, que aparecer en cada registro. Hice clic en el vnculo que pasar el ID
del elemento coincidente (establec DataNavigateUrlFields en ID) a la pgina de destino por
medio de una cadena de consulta. La propiedad DataNavigateUrlFormatString contiene
una cadena que se enviar al mtodo String.Format, junto con los campos mostrados en Da-
taNavigateUrlFields. Aqu se muestra la cadena de formato:
DetalleBusqueda.aspx?ID={0}
Proyecto | 667
Lo increble es que la pgina anterior no envi sus campos como valores de cadena. En cambio,
siguieron viviendo como objetos verdaderos. Usar la funcin CType para convertirlos a controles
TextBox y DropDownList bast para acceder a sus propiedades de control.
Uso los valores proporcionados por el usuario para generar una instruccin SQL y consultar la base
de datos para resultados. Si hay alguno, los datos resultantes se incluyen en una lista de objetos.
Dim unaEntrada As UnirEsquemaresultadosBusqueda
Dim datosInforme As Collections.Generic.List( _
Of UnirEsquemaResultadosBusqueda)
Do While infoBD.Read
' ----- Agregarlo a los datos del informe.
unaEntrada = New UnirEsquemaResultadosBusqueda
unaEntrada.ID = CInt(infoBD!ID)
unaEntrada.NombreArticulo = CStr(infoBD!Titulo)
If (IsDBNull(infoBD!Apellido) = True) Then _
usarApellido = "" Else _
usarApellido = CStr(infoBD!Apellido)
If (IsDBNull(infoBD!Nombre) = True) Then _
datosInforme.Add(unaEntrada)
Loop
Debe llamar al mtodo DataBind del control GridView o no ver ningn resultado.
Detalle de bsqueda
Cuando el usuario hace clic en uno de los vnculos de detalle en los resultados de bsqueda,
enva el ID del registro ArticuloConNombre seleccionado a la pgina SearchDetail.aspx como
una cadena de consulta. La pgina en s, que no mostrar aqu, incluye muchos controles Label
que intentan imitar la salida en el panel de detalle del formulario ItemLookup.vb en la aplicacin
principal Biblioteca. Aunque uso casi las mismas instrucciones de hoja de estilos en cascada
(Cascading Style Sheet, CSS) en esta pgina que en la aplicacin.
Cuando el manejador de eventos Load de la pgina se activa, primero examina la cadena de
consulta para extraer el ID de ArticuloConNombre proporcionado. Un ID faltante lleva a un
regreso al formulario de bsqueda principal.
idArticulo = Val(Page.Request.QueryString("ID"))
If (idArticulo <= 0) Then
Response.Redirect("Default.aspx")
Return
End If
Casi todo el cdigo de formato para esta pgina viene del archivo BusquedaArticulo.vb en la apli-
cacin principal. Consulta a la base de datos para detalles del registro ArticuloConNombre es-
pecificado, y actualiza cada etiqueta al usar estos valores. Lo nico que es interesante (adems del
hecho de que parece todo muy sencillo para el desarrollo de pgina Web) es la creacin de la tabla
de copias de artculos cerca de la parte inferior de la pgina. En la versin BusquedaArticulo.vb del
cdigo, hice a mano un conjunto HTML <table> y llen sus columnas con el estado de cada
copia disponible del elemento de biblioteca nombrado. Pens que era una pena ignorar todo ese
cdigo grandioso, as que slo lo copi casi sin cambio en el cdigo de DetalleBusqueda.aspx.vb.
Hasta ahora, no he tenido que hacer nada con HTML, excepto cuando quise agregar etiquetas
<h1> alrededor de los ttulos de pgina. Pero ya que he escrito el cdigo de generacin HTML,
y ya que las aplicaciones ASP.NET tienen por objetivo HTML, pens que poda usarlo.
Proyecto | 669
Informe de estadsticas
La pgina Estadisticas.aspx despliega la misma informacin resumida incluida en uno de los
informes del captulo 21. En el informe de estadsticas original desplegu conteos de registro de
seis diferentes tablas y las present como una lista en un formato de informe RDLC. En esta p-
gina Web hago las mismas seis consultas, genero una lista genrica de resultados y uno esa lista a
(sorpresa) un control GridView, que rpidamente se est convirtiendo en nuestro favorito. Aqu
se muestra el cdigo total de la pgina en su conjunto:
Imports System.Data
CuadriculaEstadisticas.DataSource = datosInforme
CuadriculaEstadisticas.DataBind(
)
End Sub
End Class
Slo inclu un conjunto mnimo de caractersticas en el sitio Web, y no comience a hacer chistes
acerca de mis habilidades de diseo de pginas Web. Si planeara desplegar este sitio Web, cierta-
mente hubiera habilitado algunos vnculos en la pgina DetalleBusqueda.aspx para que el usuario
pudiera hacer clic en la bsqueda para otros elementos por el mismo autor, editor, serie, etc.
Tambin hubiera agregado caractersticas especficas de cliente que nos hubieran permitido a los
usuarios revisar sus artculos prestados y cualquier multa vencida. Otra caracterstica grandiosa
para agregar hubiera sido el contenido de ayuda en lnea que dijera al cliente o administrador
cmo usar el sistema. Y eso resulta ser el tema del siguiente captulo. Suerte.
Proyecto | 671
Si hay algo que he aprendido en casi 25 aos de programacin, es que los usuarios a menudo
necesitan ayuda para ejecutar software en sus sistemas. Los programadores necesitan ayuda,
tambin; pero regresando a las computadoras: es raro que encuentre un usuario tcnicamente
experto. Si escribe aplicaciones que tienen por objetivo negocios y departamentos dentro de
organizaciones (que es lo que hago), encontrar que los usuarios tienen mucha habilidad en su
trabajo, pero no necesariamente tienen habilidades para usar una computadora. Por eso resulta
imperativo que haga los programas ms sencillos posibles.
Tambin debe agregar ayuda en lnea a sus aplicaciones. Estos documentos listos actan como
la primera oleada de soporte para las necesidades de software de los usuarios. Por supuesto, rara
vez la leen, y entonces usted (o el personal de soporte tcnico) ser realmente la primera oleada
de soporte. Pero es de alguna manera un alivio decir: Revis la ayuda en lnea, que cubre este
problema a detalle?
En este captulo analizaremos las opciones de ayuda en lnea disponibles en Visual Basic y nos con
centraremos en HTML Help 1.x, el sistema de ayuda de Windows XP estndar de Microsoft.
672
HTML Help
Los documentos RTF son de la dcada de 1980. Cuando Internet empez a entrar en el
mundo con su capacidad de generar pginas con formato hermoso mediante lenguaje comn
basado en etiqueta HTML, Microsoft decidi actualizar su sistema de ayuda a uno que usaba
documentos HTML estndar: HTML Help. Como su nombre lo indica, HTML Help est
basado en HTML. Cualquier cosa que genera HTML puede generar contenido HTML Help:
herramientas de diseado de pgina Web de terceros, procesadores de palabras, sus propias
aplicaciones, incluso el Bloc de notas. Como se esperaba, algunos vendedores disearon herra
mientas que tenan por objetivo especficamente al sistema HTML Help.
HTML Help es mejor que WinHelp, debido a su dependencia de HTML y otras tecnologas
relacionadas. Cada pgina de su archivo de ayuda en lnea es un archivo/pgina HTML separa
do. Los hipervnculos para otras pginas de ayuda son hipervnculos estndar HTML. Y HTML
Help emplea casi todas las caractersticas utilizadas en cualquier pgina Web, incluidas hojas de
estilo en cascada (Cascading Style Sheets, CSS) y secuencias de comandos Java.
Los archivos de ayuda HTML Help compilados tienen una extensin .chm, y un solo archivo
incluye contenido principal, la tabla de contenido, y un ndice predefinido de trminos. Usare
mos tecnologa HTML Help para agregar contenido de ayuda en lnea al proyecto Biblioteca.
Me saltar los detalles del sistema hasta un poco despus en el captulo.
Microsoft Help 2
La mayor parte de las aplicaciones que se venden al momento de escribir este libro usan HTML
Help, pero no todas. Una gran excepcin es Visual Studio. Su sistema de ayuda (Microsoft Help 2,
conocido como HTML Help 2.x) combina contenido HTML y XML en un conjunto de colec
ciones que funcionan juntas. Si ha instalado la versin completa de SQL Server en un sistema
con Visual Studio, comparten una interfaz de ayuda comn. Puede incluso buscar pginas en
ambas colecciones al mismo tiempo.
Assistance Platform
Windows Vista usa un nuevo sistema de ayuda denominado Assistance Platform (AP, plataforma
de asistencia). Toda la ayuda en lnea que viene con Vista est escrita en AP, pero no hay ms
que eso. Lo anterior es porque Microsoft decidi no lanzar el formato de archivo para que otros
vendedores lo usaran. Bueno, existen algunas compaas grandes y OEM que usan AP guiadas
por Microsoft, pero usted y yo no somos una de ellas.
Otros mtodos
No todas las aplicaciones usan estos sistemas de ayuda definidos por Microsoft. Algunas apli
caciones no incluyen ayuda en lnea porque estn diseados por malas personas. No, slo estoy
bromeando. Tal vez haya casos donde la ayuda en lnea no agregue valor al programa. Pero suele
ser mejor incluir algn tipo de asistencia escrita.
Las pginas HTML independientes estn slo un paso abajo de los archivos HTML Help, y
son una opcin viable para las aplicaciones simples, o las hospedadas en un sitio Web. Puede
usar otros formatos estndar, como procesamiento de palabras o documentos de texto, si no
tiene recursos para generar archivos en lnea verdaderos. Y por supuesto existen los libros, que
obtendrn mi atencin.
Visual Studio incluye una caracterstica que le permite generar documentacin de comentarios
XML agregados a cada miembro de su clase. (No analizo esto en este libro; consulte la ayuda
en lnea de Visual Studio, no est feliz de que se encuentre ah?, para informacin adicional
sobre Comentario XML.) Ni siquiera considere usar esto para las necesidades de usuario en su
propia documentacin, a menos que est desarrollando componentes basados en clase para uso
por otros desarrolladores.
Archivos de contenido
Nuestro miniproyecto incluye dos archivos de contenido: bienvenido.htm y masinfo.htm. Como
siempre he sido un especialista en tecnologa, los gener en el Bloc de notas. Aqu se muestra el
contenido de bienvenido.htm:
<html>
<head><title>Bienvenido a mi ayuda</title></head>
<body>
Bienvenido a mi ayuda. For conocer ms informacin,
<a href="masinfo.htm">haga clic aqu</a>.
</body>
</html>
Puede agregar archivos de imagen (JPEG y GIF) y vincularlos como lo hara en una pgina
Web. Asegrese de almacenar los archivos grficos en el mismo directorio (o subdirectorio) que
el archivo principal, para fcil acceso.
[FILES]
bienvenido.htm
masinfo.htm
[INFOTYPES]
El archivo cambiar conforme agreguemos los otros dos archivos que no son de contenido, pero
no por mucho.
Si compila el archivo en este momento (al usar el men de comando File Compile) y lo eje
cuta, se desplegar una ventana de ayuda muy simple, como se muestra en la figura 24-3.
Use los nuevos botones de la barra de herramientas hacia el lado izquierdo de la ventana para
agregar y modificar entradas de contenido. Primero, use el botn superior (Contents proper
ties) para editar las opciones para la tabla de contenido. En el formulario Table of Contents
Properties, quite la marca del campo Use folders instead of books y haga clic en OK.
Los siguientes dos botones el botn de libro (Insert a heading) y el de pgina/signo de inte
rrogacin (insert a page) son los botones principales utilizados para agregar nuevas entradas
a los contenidos. Hice clic en el botn Insert a page para ir al formulario Table of Contents
Entry que se muestra en la figura 24-4.
Si compila y ejecuta el archivo, ahora incluye la tabla de contenido en un panel separado, adems
de una barra de herramientas (vase la figura 24-6).
El control HelpProvider
El control HelpProvider puede agregarse a un formulario para habilitar el acceso a ayuda en
lnea. Proporciona dos experiencias principales de ayuda en lnea: 1) acceso estndar a HTML
Help compilado y 2) ayuda desplegable. Ambos mtodos colocan el enfoque en controles indi
viduales de una forma y en caractersticas de ayuda especficas para unirse a cada control.
Mtodo ShowHelp
El mtodo System.Windows.Forms.Help.ShowHelp despliega porciones especficas de un ar
chivo HTML Help basado en los argumentos pasados al mtodo. Es muy similar a la porcin
de ayuda basada en archivo del control HelpProvider, pero en formulario de mtodo. Para
desplegar una pgina especfica dentro de un archivo de ayuda, use esta sintaxis:
Windows.Forms.Help.ShowHelp(Me, "Simple.chm", _
HelpNavigator.Topic, "masinfo.htm")
Proyecto
Una vez que ha accedido a un archivo de ayuda en lnea, tiene acceso a todas las pginas de ste.
Suele ser algo bueno, porque los usuarios son curiosos. (Me refiero a que son inquisitivos y no
slo meramente objetos de curiosidad.) Pero en el caso del proyecto Biblioteca, esa curiosidad
puede llevar a temas que no son para los clientes ordinarios. La mayor parte de las caractersticas
en la aplicacin Biblioteca son slo para uso administrativo. Para mantener las cosas bajo el ma
yor control posible, el proyecto Biblioteca incluye dos archivos en lnea:
BibliotecaBasica.chm, un archivo de ayuda concentrado en clientes que describe slo las
partes del programa a las que el cliente puede acceder.
BibliotecaAdmin.chm, un archivo que tiene por objetivo administradores y bibliotecarios
que describen completamente las caractersticas de la aplicacin.
En esta seccin se generan ambos archivos de ayuda en lnea y se integra en la aplicacin Biblio
teca.
Proyecto | 683
La mayor parte de los archivos HTML tienen un vnculo uno a uno con formularios especficos
de la aplicacin. Por ejemplo, el archivo BusquedaArticulo.htm incluye el contenido de ayuda en
lnea del formulario BusquedaArticulo.vb en la aplicacin. Y esta pgina de ayuda se muestra en las
versiones bsica y administrativa del archivo. Cuando el usuario oprime F1 desde el formulario
Buscar artculo, la aplicacin intenta mostrar la pgina de ayuda en lnea BusquedaArticulo.htm.
Si el usuario es un cliente estndar, accede a esta pgina en el archivo BibliotecaBasica.chm; los
usuarios administrativos, en cambio, acceden al mismo nombre de pgina, pero desde el archivo
BibliotecaAdmin.chm.
Cada carpeta de origen de ayuda contiene archivos .hhp, .hhc y .hhk que definen el proyecto, el
contenido y los detalles de ndice, respectivamente. La versin administrativa tambin incluye
unos cuantos archivos grficos GIF.
Ya he compilado cada archivo y he colocado una copia del archivo .chm en estos directorios.
Eso significa que slo necesitamos llamar a ShowHelp de cada formulario y acceder a uno o de
los dos archivos cuando el usuario presione F1.
Pero qu pasa si el administrador nunca usa el formulario Mantenimiento.vb para configurar las
ubicaciones de los archivos de ayuda? Ya que stos tal vez estarn instalados en la misma carpeta
que el archivo de programa Biblioteca.exe, debemos ver ah automticamente. El mtodo Ini
cializarSistema en General.vb ya establece las dos variables locales a los valores almacenados
en las configuraciones.
' ----- Localizar los archivos de ayuda en linea.
ArchivoPrincipalAyuda = My.Settings.HelpFile & ""
MainAdminHelpFile = My.Settings.HelpFileAdmin & ""
Slo en caso de que estas configuraciones no existan, agreguemos algo de cdigo justo despus
de estas lneas para proporcionar acceso predeterminado a los archivos.
If (ArchivoPrincipalAyuda = "") Then ArchivoPrincipalAyuda = _
My.Computer.FileSystem.CombinePath( _
My.Application.Info.DirectoryPath, "BibliotecaBasica.chm")
If (MainAdminHelpFile = "") Then MainAdminHelpFile = _
My.Computer.FileSystem.CombinePath( _
My.Application.Info.DirectoryPath, "BibliotecaAdmin.chm")
Proyecto | 685
La mayor tarea en este captulo se relaciona con ir a cada formulario del proyecto y hacer estos
dos cambios:
Establezca la propiedad KeyPreview del formulario en True.
Agregue una llamada a AyudaEnLinea del manejador de eventos KeyDown del formulario.
Aqu se muestra el cdigo agregado al formulario CambiarUsuario.vb:
Private Sub CambiarUsuario_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles Me.KeyDown
' ----- F1 muestra la ayuda en linea.
If (e.KeyCode = Keys.F1) Then _
AyudaEnLinea(Me, "CambiarUsuario.htm")
End Sub
Algunos de los formularios procesan las peticiones de ayuda en lnea de manera un poco diferen
te que otros. ProgramaAcercaDe.vb no incluye su propia pgina de ayuda. En cambio, despliega
Bienvenido.htm. Bienvenido.vb no muestra ninguna ayuda en lnea, porque se supone que el
usuario no debe interactuar con ste. InformeVisorIntegrado.vb, el formulario que muestra cada
uno de los cinco informes integrados, despliega la ayuda para un formulario relacionado por me
dio de SeleccionarInforme.htm. El formulario BuscarEntradaSalida.vb tiene dos pginas de ayuda
en lnea asociadas: una para salida y otra para entrada de artculos. Su manejador de eventos
KeyDown selecciona la pgina adecuada basada en el modo actual del formulario.
If (e.KeyCode = Keys.F1) Then
If (ModoEntrada = True) Then
AyudaEnLinea(Me, "BuscarEntrada.htm")
Else
El panel Ayuda del formulario principal incluye botones diseados para brincar a la tabla de
contenido e ndice del archivo de ayuda en lnea actual. Agregue el manejador de eventos para
estos botones. El cdigo para ambos FormularioPrincipal.AccAyudaContenido_Click y
FormularioPrincipal.AccAyudaIndice_Click es como el cdigo en la rutina AyudaEnLi
nea genrica, excepto para la llamada final a ShowHelp.
Private Sub AccAyudaContenido_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles AccAyudaContenido.Click
' ----- Muestra la tabla de ayuda en linea de contenido.
...
Ayuda.ShowHelp(Me, archivoAUsar, _
HelpNavigator.TableOfContents)
...
End Sub
Proyecto | 687
Hablando de configurar correctamente los archivos .chm, todava tenemos que descubrir cmo
llevar la aplicacin completa (incluidos los archivos de ayuda en lnea) a la estacin de trabajo
del cliente, y a un costo que ponga comida en nuestra mesa. Veremos estos asuntos de la imple
mentacin en el siguiente captulo.
Aunque Esopo vivi hace miles de aos, tiene mucho que decirnos sobre desarrollo Web. Su
historia de Pedro y el lobo es un ejemplo perfecto. Se trata de un nio pastor que engaa a los
aldeanos varias veces al gritar, Lobo! cuando no existe ese peligro. El truco era bueno para
algunas risas, pero despus el nio descubri las consecuencias de sus acciones: no pudo hacer
que ningn aldeano comprara su oveja y tuvo que comrsela l mismo. Uff! Si tan slo el nio
hubiera aprendido a llevar apropiadamente su rebao a las manos de los aldeanos en vez de in-
ventar mentiras basadas en el lobo, nunca hubiera tenido que llegar a ese final trgico.
Entonces, Esopo claramente nos muestra qu tan importante es la implementacin. Y Micro-
soft tom esta leccin al incluir varias opciones diferentes en Visual Studio que le permitieron
instalar aplicaciones compiladas y dar soporte a archivos en una estacin de trabajo de destino.
Veremos estos mtodos en este captulo, y usaremos uno de ellos para generar un programa de
instalacin para el proyecto Biblioteca.
689
Ya que estar desarrollando interactivamente su sitio Web, tal vez no quiera usar este mtodo en un
servidor de produccin. En cambio, puede desarrollar de manera local en un directorio o en un ser-
vidor Web de desarrollo, y despus publicar el sitio en el servidor de produccin. Esto es tan fcil
como establecer la ubicacin HTTP desde el inicio. Con el sitio Web abierto en Visual Studio,
seleccione el men de comando Build Publicar sitio Web y especifique el URL del nuevo sitio
Web. No se requiere programa de instalacin.
ASP.NET es cuidadoso acerca de cmo maneja los archivos en su aplicacin. No publicar su
cdigo fuente. Copiar su archivo web.config al servidor (es un archivo requerido), que puede
contener su cadena de conexin de base de datos. Pero un servidor Web ASP.NET configurado
apropiadamente mantendr este archivo fuera de ojos fisgones.
Paso 1
El primer paso del asistente slo dice Bienvenido, as que haga clic en Siguiente y entre al
trabajo real.
Paso 2
El paso 2 le pregunta el tipo de proyecto de instalacin que habr de generarse. En lo personal,
pienso que pudo haberlo descubierto a partir del contenido de los proyectos ya cargados, pero
si el asistente hace todo, para qu necesitara el mundo programadores como nosotros? Existen
cuatro opciones, como se muestran en la figura 25-3.
Las primeras dos opciones crean archivos de instalacin completos para cualquier aplicacin
de escritorio o basada en Web. (La instalacin basada en Web se entregara a un administrador de
sitio Web para instalacin en el servidor.) Los mdulos combinados le permiten crear una porcin
de una instalacin que puede despus combinarse en un archivo MSI completo. sta es una bue-
na opcin si est diseando una biblioteca que se usar para varias aplicaciones, pero no es til
por s sola. La opcin de archivo CAB crea un archivero de archivos que pueden instalarse al usar
una tecnologa vieja de distribucin de archivos. Es tambin el sistema de distribucin utilizado
para dispositivos porttiles. Como tengo como objetivo una aplicacin de escritorio, seleccionar
Crear un programa de instalacin de una aplicacin para Windows y har clic en Siguiente.
Paso 3
Aunque puede crear un programa de configuracin que simplemente instale varios archivos que
devoren su disco duro, por lo general generar un proyecto de instalacin basado en archivos o
salida compilada de otros proyectos. El tercer paso del asistente le pide que incluya elementos
de otros proyectos encontrados en la solucin activa de Visual Studio. He decidido incluir el
archivo EXE compilado desde mi proyecto de escritorio, como se muestra en la figura 25-4.
Por lo general, no quiero incluir mi cdigo fuente en el proyecto de instalacin, as que dejo ese
elemento sin marca. Pero el elemento Archivos de contenido puede ser til. Si mi proyecto tiene
un archivo de ayuda en lnea compilado (con una extensin de archivo .chm), podra agregarlo
como un archivo de contenido estndar para el proyecto principal mediante el comando de
men Proyecto Agregar elemento existente. Ese archivo se clasificara como Contenido, y
podra moverse a esta instalacin de proyecto a travs de la seccin Archivos de contenido. Pero
hay otras formas de incluir ayuda en lnea en la instalacin, que veremos en el siguiente paso. Por
ahora, me quedar con la seccin Resultado principal y har clic en el botn Siguiente.
Paso 4
En este paso puede agregar cualquier otro archivo no especfico de proyecto que quiera a la ins-
talacin del proyecto (vase la figura 25-5). Los archivos Lame, el contenido de ayuda en lnea,
los acuerdos de licencia, las imgenes de sus hijos y casi cualquier cosa puede incluirse aqu. No
tengo nada ms que agregar. Haga clic en Siguiente.
Figura 25-5. Agregue esos otros archivos que siempre han querido una oportunidad para el estrellato en la instalacin
de proyecto.
Paso 5
El paso final despliega un resumen de las opciones que decidi (vase la figura 25-6). Bueno,
ese asistente fue muy sencillo. Tuvimos que trabajar en slo tres de los cinco pasos. Haga clic en
Finalizar para completar el asistente.
La ventana principal en la figura 25-7 es uno de los varios editores que le permiten personalizar
el proyecto de instalacin. Puede acceder a cada editor a travs del comando de men Ver
Editor, o al usar los botones de la barra de herramientas en el panel Explorador de soluciones.
Editor Sistema de archivos
Es el editor que ya vio en la figura 25-7. Presenta una vista estndar de carpeta/elemento
de porciones del sistema de archivos del sistema de destino. A travs de esta jerarqua,
Este panel incluye campos que le permiten establecer el nmero de versin del paquete de insta-
lacin publicado. Si modifica este nmero de versin y vuelve a publicar la aplicacin, el cdigo
de implementacin personalizado que agregue a la aplicacin puede detectar la nueva versin e
iniciar una actualizacin desde la ubicacin de distribucin.
Proyecto
Seleccion una implementacin estndar Windows Installer porque pens que coincidira ms
de cerca con las necesidades del usuario tpico del sistema Biblioteca. La aplicacin Biblioteca
est destinada a ser una caracterstica permanente en la estacin de trabajo de destino, as que es
probable que alguien con conocimiento de tecnologa de la informacin o privilegios adminis-
trativos realice las instalaciones reales. Como es un producto con licencia, hay poca probabilidad
de que pudiera colocar copias de la instalacin Biblioteca desde mi sitio Web pblico. Una
distribucin en CD (comn para instalaciones MSI) es el medio esperado. Adems, como es una
pieza de software de calidad de un vendedor confiable (se soy yo), no hay necesidad de una caja de
arena protectora. An as, la aplicacin incluye varios archivos, incluidos dos de ayuda en lnea;
entonces una instalacin XCopy sera una carga. A todo esto, una instalacin con MSI estndar
es el mejor plan de implementacin.
Planeacin de la implementacin
El Asistente para el proyecto de instalacin agrega automticamente mi ensamblado de proyecto
al archivo MSI, pero estoy seguro de que se necesitan otros archivos para desplegar apropiada-
mente el proyecto Biblioteca. Una vista rpida a travs de captulos previos revela la siguiente
lista de requisitos de archivado:
.NET Framework 3.5
ste debe estar instalado en el sistema de destino para ejecutar la aplicacin Biblioteca. El
programa de instalacin necesita instalar el marco conceptual automticamente si no est
ya en el sistema objetivo.
Biblioteca.exe
ste es el ensamblado principal. La instalacin sera intil sin ste.
Proyecto | 701
Los primeros pasos son iguales a los que dimos antes en este captulo. Una vez que tenga el
proyecto Biblioteca cargado y guardado en su carpeta de destino, agregue un nuevo proyecto
de instalacin al usar el men de comando Archivo Agregar Nuevo Proyecto. Seleccio-
ne Asistente para el proyecto de instalacin como plantilla, inserte InstalacionBiblioteca
como Nombre, y use la carpeta del proyecto Biblioteca que acaba de guardar como Ubicacin.
Aplique las siguientes configuraciones dentro del asistente:
En el paso 2 seleccione Crear un programa de instalacin de una aplicacin para Windows.
En el paso 3 seleccione Resultado principal de Biblioteca, de la lista.
En el paso 4 ubique y agregue los archivos BibliotecaBasica.chm y BibliotecaAdmin.chm. En
el directorio de instalacin de este libro puede encontrarlos en el subdirectorio denominado
Ayuda en lnea.
Complete el asistente y use el comando de men Archivo Guardar todo. Cuando se le pida
guardar el archivo de solucin (Biblioteca.sln), slo almacnelo en el directorio de proyecto Bi-
blioteca, que debe estar seleccionado.
Como antes, el proyecto de instalacin abre el Editor Sistema de archivos. Antes de hacer cual-
quier cambio dentro del editor, configuremos algunas propiedades en el nivel de la instalacin.
Haga clic en InstalacionBiblioteca en el panel Explorador de soluciones y modifique las siguien-
tes propiedades en el panel Propiedades:
Establezca la propiedad Author en Tim Patrick, o su propio nombre.
Establezca la propiedad Manufacturer en ACME.
Establezca la propiedad ManufacturerURL en http://www.timaki.com o cualquier sitio
Web que desee usar.
Establezca la propiedad ProductName en Biblioteca ACME.
Establezca la propiedad Title en Instalacin de la biblioteca ACME.
Debido a que el Editor Sistema de archivos est abierto, hagamos algunos cambios ah. Cuando
agregamos el ensamblado Biblioteca.exe a travs del asistente, descifr todas las dependencias
necesarias. No slo el programa principal y los elementos de archivo de ayuda aparecen en la
seccin Carpeta de la aplicacin, sino tambin tres DLL adicionales; todos solan ejecutar los
informes de Biblioteca (vase la figura 25-9).
Ya que Microsoft proporciona estos tres DLL como parte de .NET, no tiene mucho sentido
almacenarlos en mi propio directorio de instalacin de la aplicacin. Deben ir en el cach de
ensamblado global (GAC, Global Assembly Cache), la carpeta de sistema especial que mantiene
los ensamblados .NET compartidos. GAC no es una de las opciones de carpeta desplegadas
en el editor, pero puede serlo. Asegrese de que el panel de la izquierda del Editor del Sistema
de archivos est seleccionado (el que tiene Sistema de archivos en Equipo de destino) y use el
comando de men Accin Agregar carpeta especial Carpeta Cach de ensamblado global.
Una nueva carpeta, Carpeta Cach de ensamblado global, aparece en el panel de la izquierda.
Seleccione el elemento Carpeta de la aplicacin de nuevo y arrastre los tres elementos DLL al
elemento Carpeta Cach de ensamblado global como se muestra en la figura 25-10.
Figura 25-10. Haga que los tres archivos DLL sean responsabilidad de alguien ms.
Agreguemos dos accesos directos al sistema del usuario durante la instalacin: uno en el escritorio
y uno en la seccin Programas del men Inicio. Ambos mtodos abreviados apuntan al ensambla-
do Biblioteca.exe principal. Al Asistente para el proyecto de la instalacin anticip nuestras nece-
sidades al agregar las carpetas Escritorio de usuario y Men programas del usuario al Editor Sistema
de archivos. Todo lo que tenemos que hacer es agregar un acceso directo a cada carpeta.
Empecemos con el escritorio. Seleccione la carpeta Escritorio de usuario y despus haga clic con el
botn derecho en el panel de la derecha (donde aparecern los archivos). Del men contextual,
seleccione el comando de men Crear nuevo acceso directo. (Este mismo comando est disponi-
ble en el men Accin principal cuando el panel del lado derecho est activo.) Aparece el cuadro
de dilogo Seleccionar elemento en el proyecto, como se muestra en la figura 25-11. Explore
el elemento Carpeta de la aplicacin y seleccione Resultado principal de biblioteca (Activo).
El nuevo acceso directo aparece en el panel de la derecha, esperando que le d un nombre ms
significativo. Asgnele el nombre Biblioteca ACME.
Proyecto | 703
Para crear el mismo acceso directo en el men Inicio, siga los pasos del prrafo anterior, pero
inicie desde la carpeta Men Programas del usuario en lugar de Escritorio del usuario.
Agregar estos accesos directos fue una buena idea, pero despus de que instalo algn software
nuevo, siempre borro inmediatamente cualquier acceso directo que se agrega al escritorio. Agre-
gar un cono en la carpeta Programas del men Inicio tiene sentido, pero me gusta mantener un
escritorio limpio y agradable. Rase si quiere, pero mantener el escritorio libre de desorden es lo
que me hizo un autor y desarrollador famoso en todo el mundo.
Lo que necesitamos es una forma de alterar el comportamiento del programa de instalacin para
que no cree el cono de escritorio, si el usuario no quiere uno. El proyecto de instalacin propor-
ciona una forma de hacerlo. Primero, necesitamos agregar una peticin donde el usuario indique
una preferencia de cono de escritorio, y despus necesitamos actuar sobre esa preferencia. El
primer paso consiste en alterar la interfaz de usuario del programa de instalacin. Estos cambios
ocurren con el Editor Interfaz de usuario. Despliegue este editor al usar el comando de men
Ver Editor Interfaz de usuario. Aparece el editor Interfaz de usuario, como se muestra en
la figura 25-12.
El editor Interfaz de usuario se divide en dos tipos de instalacin principales: Instalar e Instala-
cin administrativa. La rama administrativa se usa slo cuando un administrador quiere almace-
nar la imagen de instalacin en una carpeta de red compartida. No permite los tipos de cambios
que queremos hacer. Entonces, enfoqumonos en la rama Instalar estndar, que maneja las ins-
talaciones de usuario estndar en una estacin de trabajo de cliente. Ambas ramas incluyen indi-
cadores paso a paso que aparecen al usuario durante el proceso de instalacin. Los indicadores de
recoleccin de datos slo pueden agregarse a la entrada Inicio en la rama principal Instalar.
Durante la instalacin real, la interfaz de usuario interacta con el usuario en una forma parecida
a un asistente. Durante la fase Inicio, el programa de instalacin recolecta los deseos del usuario
para el resto del proceso. Una vez que esta seccin termina, la instalacin contina hasta que
se completa o falla. Lo que queremos hacer es insertar un nuevo paso en el proceso de asisten-
te, desplegando una casilla de verificacin que le pregunte al usuario si el cono de escritorio
debe aparecer o no. Los campos de recoleccin de datos adicional como stos se agregan a travs
de nuevos cuadros de dilogo. Y se resulta ser un cuadro de dilogo que incluye una casilla de
verificacin personalizable. En la rama Instalar, haga clic con el botn derecho en el elemento
Inicio y seleccione Agregar cuadro de dilogo del men contextual. La ventana Agregar cuadro
de dilogo, como se muestra en la figura 25-13, despliega los cuadros disponibles. Seleccione el
elemento Casillas (A) de la lista y haga clic en Aceptar.
El nuevo elemento Casilla (A) aparece en la seccin Instalar/Inicio. Use el ratn para arrastrarlo
hasta que aparezca entre los cuadros de dilogo Pantalla de bienvenida y Carpeta de instalacin.
El cuadro de dilogo Casilla le permite desplegar hasta cuatro selecciones de casilla de verifica-
cin con leyendas personalizadas. Asegrese de que est seleccionado en el esquema del dilogo
y despus use el panel Propiedades para establecer estas nuevas propiedades del dilogo:
Escriba Opciones de instalacin en la propiedad BannerText. Este texto aparecer cerca
de la parte superior de la ventana de dilogo, desplegando un ttulo principal grande.
En la propiedad BodyText escriba Seleccione las opciones que desee usar para esta insta-
lacin.
Proyecto | 705
ste es el nombre que le dimos a la primera casilla de verificacin en el diseo del dilogo.
Durante la instalacin, el programa de instalacin revisa la seleccin del usuario y modifica la
actualizacin de escritorio como se pida.
Algo que no agregar a mi versin del programa de instalacin es la fuente de cdigo de barras.
Lamentablemente, no he adquirido una licencia para distribuir una fuente de tercero a usted o
nadie ms que lea este libro. La buena noticia es que le ahorr 10 dlares en el costo del libro. La
mala noticia es que tendr que decirle cmo agregar la fuente, pero no lo haremos en realidad.
Realmente, tal vez adivine cmo hacerlo. La carpeta Fonts es una de las carpetas especiales dispo-
nibles en el editor Sistema de archivos. Cuando el elemento Sistema de archivos en el equipo de
destino, en el panel de la izquierda, use el comando de men Accin Agregar carpeta especial
Carpeta Fuentes. Despus agregue el archivo de fuente original (un archivo TrueType .ttf) a la
seccin de carpetas Fuentes. No podr agregar esta fuente directamente desde su carpeta Windows\
Fonts. En cambio, necesitar obtener el archivo .ttf y usar eso. En la estacin de trabajo de destino,
el programa de instalacin instalar y registrar apropiadamente la fuente para uso en Windows.
El proyecto de instalacin est completo. Lo nico que queda por hacer es generar el archi-
vo MSI. Tal vez no lo haya notado, pero Visual Studio incluye diferentes configuraciones de
compilacin en cada proyecto. Las dos configuraciones predeterminadas son Depuracin y
Liberacin, y cada una puede generar un conjunto distinto de archivos de salida finales cuando
compila su aplicacin. Por lo general, su proyecto est establecido en Depuracin, pero puede
cambiarlo con el Administrador de configuracin. En Visual Studio seleccione el comando de
men Generar Administrador de configuracin para desplegar el formulario del adminis-
trador (vase la figura 25-15). En este formulario cambie la configuracin Configuracin de
soluciones activas de Debug a Release y despus haga clic en el botn Cerrar.
Proyecto | 707
Es tiempo de generar el archivo MSI. Haga clic con el botn derecho en la raz InstalarBiblioteca
en el panel Explorador de soluciones, y seleccione Generar del men contextual. En slo unos
cuantos segundos, su archivo MSI estar horneado y listo para comer. Lo encontrar en el sub-
directorio Release del proyecto de instalacin. Este directorio tambin incluye un archivo Setup.
exe que acta como arranque. Cualquier estacin de trabajo con el sistema Windows Installer
presente funcionar con el archivo MSI simple, pero proporcionar un archivo Setup.exe agrega
un nivel de confort a los usuarios novatos.
El medio de distribucin
Odio cuando los usuarios vienen a mi oficina e intentan copiar el archivo MSI directamente de
mi disco duro. Encuentro que proporcionar el archivo en un CD tiende a mejorar la relacin
vendedor-cliente. As que generemos un CD para uso de cliente.
El CD de distribucin contiene todo el contenido necesario para la biblioteca de personal de
tecnologa de la informacin para soporte a la aplicacin. Contiene distintos directorios para
cada tipo de contenido. Aqu est lo que planeo colocar en la raz del CD:
Lame.htm, un archivo HTML que despliega informacin acerca de contenidos del CD.
Base de datos, un directorio que contiene la secuencia de comandos de creacin de base de
datos, Script de creacin de la base de datos.sql.
Licencia, un directorio que contiene el archivo de licencia del usuario especfico, LicenciaBi-
blioteca.lic.
Instalacin, un directorio que contiene el archivo MSI principal, InstalacionBiblioteca.msi.
Recursos tcnicos, un directorio que contiene la documentacin de soporte tcnico, Kit de
recursos de la Biblioteca ACME.pdf.
Web, un directorio que contiene un cdigo fuente completo para el sitio Web Biblioteca que
creamos en el captulo 22. El administrador puede usar esto como la base de un sitio Web
Biblioteca expandido.
Proyecto | 709
Copiar todos estos directorios y archivos a un CD y agregar una etiqueta bonita debe producir
un bibliotecario feliz.
Nos estamos acercando rpidamente al final de este libro. Slo falta un captulo. Voltee la pgina
para descubrir qu contenido emocionante encontrar ah.
El proyecto Biblioteca
El proyecto Biblioteca est lleno de caractersticas que tienen por objetivo organizaciones peque-
as estilo biblioteca. Pero tal vez no cumpla las necesidades de todas las personas. Y eso est bien.
Los usuarios saben su direccin y nmero telefnico; sabr de ellos. Cuando ellos llamen, puede
decirles que el software no est diseado para todos; ningn software puede estarlo. Todo el soft-
ware, incluidas aplicaciones de propsito general como Visual Studio, nunca pueden cumplir
las necesidades de cada persona u organizacin. Lo que es importante es que las caractersticas
incluidas en el proyecto cumplen las necesidades de la audiencia planeada. La audiencia puede
ser el pblico que usa catlogo con tarjetas, o puede ser slo una pequea biblioteca con un
miembro de personal de medio tiempo.
An as, siempre hay espacio para mejoras. Debido a que la audiencia de destino real del proyec-
to Biblioteca fue usted (el estudiante de Visual Basic y .NET) no tiene todas las caractersticas
que casi todas las bibliotecas requieren. Al revisar rpidamente el cdigo fuente, se me ocurrieron
al menos los siguientes cambios que pueden hacer que el proyecto lleve mucho ms valor a los
administradores de biblioteca y usuarios:
Registro de errores
La aplicacin incluye deteccin de errores rudimentaria y caractersticas de manejo, pero
pueden definitivamente ser mejoradas. La caracterstica de registro utilizada en el mtodo
ErrorGeneral de la aplicacin (que incluye una llamada a My.Application.Log.Wri-
teException) enva el contenido escrito a cualquiera que escucha el protocolo registrado.
711
Como otro ejemplo, considere la antigua instruccin Exit Sub. Todava existe en Visual Basic
para .NET, pero una nueva palabra clave Return realiza el mismo trabajo de terminar inmedia-
tamente desde el mtodo actual. (Return tena un significado diferente en Visual Basic antes que
.NET, pero ahora slo es un mtodo de salida.) Puede usar Exit Sub o Return en su cdigo,
tienen una funcionalidad idntica. Hay programadores que consideran la antigua instruccin
Exit Sub como si fuera (bueno) vieja. Pero a diferencia de mis reservas para dejar mi mtodo fa-
vorito MsgBox, he cambiado sin reservas a la nueva instruccin Return. Si fuera slo cuestin de
comparacin entre Exit Sub y Return, no hubiera hecho el cambio. Pero existe un problema
relacionado de la diferencia de Exit Function y Return. Nunca estuve feliz con la forma en
que las funciones antes de .NET de Visual Basic obtenan los valores de regreso a travs de una
Resumen
Ahora que realmente ha llegado al final del libro, puede leer los apndices e ndices si todava
quiere ms. Pero una mejor solucin sera descubrir si he elaborado la nueva edicin del libro y
comprarla. Ja!
Y gracias por tomarse el tiempo de leer Programacin con Visual Basic 2008. Lo escrib para que
pudiera expandir su entendimiento y experiencia de un tema prctico y que poda disfrutarse:
Visual Basic. Y disfrutable es la palabra clave. Nadie tiene que ser un programador de compu
tadoras, sin importar lo que los historiadores digan. Debe tomar la funcin de un desarrollador
de Visual Basic slo si realmente siente placer en ayudar a otras personas a volverse ms produc-
tivos mediante software especializado o general. Si, incluso despus de leer este libro, encuentra
que hacer cdigo es un trabajo aburrido y pesado, le recomiendo la industria de los servicios de
alimentos como una alternativa.
Y todos ustedes que todava estn emocionados por programar en Visual Basic, divirtanse todo
lo que puedan. Microsoft est actualizando constantemente el lenguaje y la interfaz de Visual
Studio se presenta de una manera en que realmente puede disfrutar mientras programa. Por qu
piensa que Microsoft coloca todas estas caractersticas de animacin? Tome tiempo para ir ms
all de lo mundano en su cdigo y en sus interfaces de usuario. Desafese a s mismo a probar
nuevas caractersticas dentro del lenguaje y en el marco conceptual. Y encima de todo, sonra
cada vez que complete con xito un proyecto. Su autor y sus usuarios se lo agradecern.
Resumen | 717
Usted tiene en sus manos ms que slo un libro. Sostiene una idea. No, espere, eso es lo que
tiene cuando lee un libro de filosofa. En este caso, lo que tambin obtiene es software (software
gratuito). Y todo se encuentra en el sitio Web de este libro:
www.mcgraw-hill-educacion.com
Cuando descarga y ejecuta el programa de instalacin proporcionado en el sitio Web, los si-
guientes elementos se agregan a su sistema:
Una estructura de directorio con todo el cdigo fuente y la documentacin especfica de
todos los captulos.
Un archivo vsi que instala un conjunto de plantilla de proyecto de Visual Studio Project.
Cada plantilla crea un nuevo proyecto basado en las imgenes de cdigo fuente de antes
y despus para casi todos los captulos del libro. Una vez que instala este archivo, tendr
la opcin de acceder a los procesos especficos de cada captulo empleando el comando de
men Archivo Nuevo proyecto en Visual Studio.
Un directorio de fragmentos de cdigo que le permiten seguir la accin en el Proyecto de
cada captulo, sin que tenga que volver a escribir cada lnea de cdigo impresa en el libro.
La instalacin requiere casi 50 MB de espacio en disco. En este apndice se analizan los proce-
dimientos de descarga e instalacin.
719
Para completar la instalacin, haga clic en el botn Siguiente, y despus otro en el botn Fi-
nalizar. La prxima vez que ejecute Visual Studio, todas las plantillas instaladas del proyecto
aparecern cuando use el comando de men Archivo Nuevo proyecto.
Haga clic en el botn Agregar y vaya al directorio donde extrajo el contenido descargado del
libro. Busque el directorio Fragmentos de cdigo, seleccione el subdirectorio Programacin con
Visual Basic 2008 y haga clic en el botn Seleccionar carpeta. Cuando el control regrese al for-
mulario Administrador de fragmentos de cdigo, haga clic en el botn Aceptar para completar
la instalacin.
Cuando descargue e instale el software proporcionado con este libro, usted expresa su acuerdo
con los trminos del acuerdo de licencia de software.
Trminos de uso
Los componentes de cdigo fuente y software proporcionados con Programacin con Visual Basic
2008 (conocidos de manera colectiva como el software) estn diseados para usarse con ese
libro, y slo estn disponibles para quienes obtienen y usan el libro. Como tal, el software est
cubierto por los derechos de autor y las licencias del propio libro. Sin embargo, hay algunos
trminos y condiciones adicionales que deben hacer el software an ms til para sus actividades
de desarrollo y aprendizaje:
Uso del software con el libro
Puede instalar y usar el software junto con la lectura del texto. Si utiliza varias estaciones en
sus empeos de aprendizaje, sintase en la libertad de instalar el software en cada uno de
esos sistemas.
Distribucin del software proporcionado
No puede empaquetar, distribuir, vender ni poner a disposicin de otros las aplicaciones
parciales o completas proporcionadas con el libro. Afirmar que este trabajo es suyo, y tratar
de distribuirlo o venderlo como tal, es una mala, muy mala idea.
Uso de partes del software en sus proyectos
Puede usar parte de este software en sus propias aplicaciones y proyectos de desarrollo. Si
incluye partes significativas del software en su trabajo derivado, por favor d crdito a quien
crdito merece, y haga saber que su aplicacin emplea el til contenido proporcionado con
Programacin en Visual Basic 2008.
Agradecimientos
El software fue desarrollado por Tim Patrick, autor de Programacin en Visual Basic 2008.
Tim Patrick y OReilly Media, Inc. ponen con gusto este software a su disposicin para su
enseanza y disfrute.
722
725
726 | ndice
ndice | 727
728 | ndice
ndice | 729
730 | ndice
ndice | 731
732 | ndice
ndice | 733
734 | ndice
ndice | 735
736 | ndice
ndice | 737
738 | ndice
ndice | 739
740 | ndice
ndice | 741
742 | ndice
ndice | 743
744 | ndice
ndice | 745
746 | ndice
ndice | 747
748 | ndice
ndice | 749
750 | ndice
ndice | 751
752 | ndice
ndice | 753
754 | ndice
ndice | 755
756 | ndice
ndice | 757
Colofn
El animal en la portada de Programacin con Visual Basic 2008 es un pato cabeza de bfalo
(Bucephala albeola). El nombre alude a la forma de la cabeza, distintiva de estas especies. Los
cabeza de bfalo macho son de color blanco y negro con una larga franja blanca que se extiende
de los ojos a la parte trasera de la cabeza; las hembras son ms plidas, ms pequeas y tienen
una pequea franja blanca en los carrillos. Ambos sexos estn caracterizados por cuellos cortos y
picos estrechos de color gris.
Con variaciones en tamao que van de 35 a 42 centmetros y en peso de 250 a 650 gramos, los
cabeza de bfalo son los patos ms pequeos que se sumergen en el agua en Estados Unidos. A
diferencia de otros patos que hacen lo mismo, puede alzar el vuelo directamente desde el agua sin
tener que correr por la superficie. Viven en lagos, ros y bahas de Canad y el norte de Estados
Unidos, migrando a las aguas costeras del Atlntico, el Pacfico y del Golfo hasta zonas del sur
como Mazatln en los meses de invierno. Anidan en cavidades de lamos hechas por pjaros
carpinteros.
La dieta del pato cabeza de bfalo consiste de insectos frescos y de agua salada, caracoles, crus-
tceos y plantas. Bucean en busca de comida y la tragan bajo el agua. Los patos cabeza de bfalo
tienden a permanecer en grupo, uno o dos de ellos se alimentan mientras los dems vigilan por
cualquier posible peligro. Aunque no son apreciados entre los cazadores de patos, los cabeza de
bfalo son cazados por deporte en Estados Unidos y Canad y comprenden casi 2% de la caza
de aves acuticas en Amrica del Norte. No es una especie amenazada, pero la degradacin de su
hbitat es una preocupacin creciente. Debido a que los patos regresan a la misma zona donde
se alimentan cada ao, la cosecha y deforestacin excesiva puede tener impacto en su poblacin
si no se le vigila con cuidado.
La imagen de la portada es de la Natural History, de Johnson. La fuente de la portada es Adobe
ITC Garamond. La fuente del texto de Linotype Birka; la fuente de los encabezados es Adobe
Myriad Condensed; y la fuente del cdigo es TheSansMonoCondensed de LucasFont.
Visual Basic
claramente y darse la oportunidad de probarlos. Este
libro le da estos elementos. No slo conseguir una tanto como ste. Excelente
firme comprensin sobre conceptos de desarrollo de software en cobertura, perfecto para la
Visual Basic, tambin tendr prctica real al disear, construir y
audiencia a la que est
desplegar una aplicacin completa orientada a base de datos.
dirigido. Descripciones
2008
Cada captulo de Programacin con Visual Basic 2008 ofrece
explicaciones claras, repletas de cdigo de ejemplo para concisas, claras, exactas.
ayudarle a construir su aprendizaje durante el proceso de Es un ganador.
desarrollo. Con esta obra completa, usted: -Ken Getz
Consultor senior
Adquirir experiencia prctica en el desarrollo de aplicaciones MCW Technologies
.NET, desde el diseo hasta la implementacin.
Disear bases de datos con SQL Server y ADO.NET.
Construir aplicaciones de escritorio complejas con Tim Patrick es arquitecto de software
formularios de Windows y aplicaciones Web con ASP.NET. y desarrollador; tiene 25 aos de
experiencia en diseo y construccin
Dominar las nuevas caractersticas de VB 2008 como de soluciones personalizadas de
expresiones lambda y tipos null. software. MVP de Microsoft y
Acelerar los procesos con consultas LINQ y generacin desarrollador de soluciones
de XML dinmico. certificado de Microsoft, Tim ha
publicado cinco tutoriales y
Descubrir cmo dar licencias, documentar, implementar
referencias sobre desarrollo de
y dar soporte a sus aplicaciones.
Visual Basic, junto con varios
Extender an ms su aprendizaje, usando el cdigo fuente artculos. Entre sus libros se incluyen
de aplicaciones incluido. Visual Basic 2005 in a Nutshell y
Visual Basic 2005 Cookbook.
Obtendr la mentalidad de un desarrollador al adquirir
habilidades de programacin cotidianas.
Patrick
Tim Patrick